about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules')
-rw-r--r--nixpkgs/nixos/modules/config/console.nix21
-rw-r--r--nixpkgs/nixos/modules/config/fonts/fontdir.nix47
-rw-r--r--nixpkgs/nixos/modules/config/fonts/fonts.nix12
-rw-r--r--nixpkgs/nixos/modules/config/ldap.nix35
-rw-r--r--nixpkgs/nixos/modules/config/malloc.nix2
-rw-r--r--nixpkgs/nixos/modules/config/no-x-libs.nix3
-rw-r--r--nixpkgs/nixos/modules/config/pulseaudio.nix10
-rw-r--r--nixpkgs/nixos/modules/config/swap.nix2
-rw-r--r--nixpkgs/nixos/modules/config/system-path.nix4
-rw-r--r--nixpkgs/nixos/modules/config/update-users-groups.pl30
-rw-r--r--nixpkgs/nixos/modules/config/users-groups.nix25
-rw-r--r--nixpkgs/nixos/modules/config/zram.nix20
-rw-r--r--nixpkgs/nixos/modules/hardware/acpilight.nix1
-rw-r--r--nixpkgs/nixos/modules/hardware/all-firmware.nix1
-rw-r--r--nixpkgs/nixos/modules/hardware/keyboard/zsa.nix27
-rw-r--r--nixpkgs/nixos/modules/hardware/opentabletdriver.nix58
-rw-r--r--nixpkgs/nixos/modules/hardware/rtl-sdr.nix20
-rw-r--r--nixpkgs/nixos/modules/hardware/video/nvidia.nix2
-rw-r--r--nixpkgs/nixos/modules/i18n/input-method/default.nix3
-rw-r--r--nixpkgs/nixos/modules/i18n/input-method/default.xml25
-rw-r--r--nixpkgs/nixos/modules/i18n/input-method/hime.nix14
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix9
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/iso-image.nix7
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix32
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/sd-image-raspberrypi4.nix32
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/sd-image.nix9
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix2
-rw-r--r--nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix8
-rw-r--r--nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix2
-rw-r--r--nixpkgs/nixos/modules/installer/tools/nixos-enter.sh3
-rw-r--r--nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl11
-rw-r--r--nixpkgs/nixos/modules/installer/tools/nixos-install.sh4
-rw-r--r--nixpkgs/nixos/modules/installer/tools/nixos-rebuild.sh2
-rw-r--r--nixpkgs/nixos/modules/installer/tools/tools.nix101
-rw-r--r--nixpkgs/nixos/modules/misc/documentation.nix36
-rw-r--r--nixpkgs/nixos/modules/misc/ids.nix16
-rw-r--r--nixpkgs/nixos/modules/misc/locate.nix67
-rw-r--r--nixpkgs/nixos/modules/module-list.nix30
-rw-r--r--nixpkgs/nixos/modules/profiles/hardened.nix9
-rw-r--r--nixpkgs/nixos/modules/programs/bandwhich.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/chromium.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/command-not-found/command-not-found.pl15
-rw-r--r--nixpkgs/nixos/modules/programs/firejail.nix46
-rw-r--r--nixpkgs/nixos/modules/programs/fish.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/msmtp.nix104
-rw-r--r--nixpkgs/nixos/modules/programs/neovim.nix165
-rw-r--r--nixpkgs/nixos/modules/programs/proxychains.nix165
-rw-r--r--nixpkgs/nixos/modules/programs/ssmtp.nix22
-rw-r--r--nixpkgs/nixos/modules/programs/sway.nix5
-rw-r--r--nixpkgs/nixos/modules/programs/vim.nix14
-rw-r--r--nixpkgs/nixos/modules/programs/wshowkeys.nix22
-rw-r--r--nixpkgs/nixos/modules/programs/x2goserver.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/xwayland.nix45
-rw-r--r--nixpkgs/nixos/modules/rename.nix1
-rw-r--r--nixpkgs/nixos/modules/security/acme.nix28
-rw-r--r--nixpkgs/nixos/modules/security/acme.xml24
-rw-r--r--nixpkgs/nixos/modules/security/apparmor.nix6
-rw-r--r--nixpkgs/nixos/modules/security/doas.nix11
-rw-r--r--nixpkgs/nixos/modules/security/hidepid.nix4
-rw-r--r--nixpkgs/nixos/modules/security/pam.nix69
-rw-r--r--nixpkgs/nixos/modules/security/pam_mount.nix14
-rw-r--r--nixpkgs/nixos/modules/security/sudo.nix13
-rw-r--r--nixpkgs/nixos/modules/security/systemd-confinement.nix2
-rw-r--r--nixpkgs/nixos/modules/security/wrappers/default.nix11
-rw-r--r--nixpkgs/nixos/modules/services/admin/salt/master.nix4
-rw-r--r--nixpkgs/nixos/modules/services/admin/salt/minion.nix2
-rw-r--r--nixpkgs/nixos/modules/services/audio/jack.nix3
-rw-r--r--nixpkgs/nixos/modules/services/audio/mpd.nix72
-rw-r--r--nixpkgs/nixos/modules/services/backup/syncoid.nix52
-rw-r--r--nixpkgs/nixos/modules/services/backup/tarsnap.nix4
-rw-r--r--nixpkgs/nixos/modules/services/cluster/k3s/default.nix4
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix2
-rw-r--r--nixpkgs/nixos/modules/services/computing/slurm/slurm.nix68
-rw-r--r--nixpkgs/nixos/modules/services/computing/torque/mom.nix2
-rw-r--r--nixpkgs/nixos/modules/services/computing/torque/server.nix2
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/gitlab-runner.nix2
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix3
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix33
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix6
-rw-r--r--nixpkgs/nixos/modules/services/databases/cassandra.nix15
-rw-r--r--nixpkgs/nixos/modules/services/databases/foundationdb.nix2
-rw-r--r--nixpkgs/nixos/modules/services/databases/mongodb.nix2
-rw-r--r--nixpkgs/nixos/modules/services/databases/openldap.nix454
-rw-r--r--nixpkgs/nixos/modules/services/databases/postgresql.nix15
-rw-r--r--nixpkgs/nixos/modules/services/databases/redis.nix9
-rw-r--r--nixpkgs/nixos/modules/services/databases/riak-cs.nix202
-rw-r--r--nixpkgs/nixos/modules/services/databases/riak.nix2
-rw-r--r--nixpkgs/nixos/modules/services/databases/stanchion.nix194
-rw-r--r--nixpkgs/nixos/modules/services/databases/victoriametrics.nix2
-rw-r--r--nixpkgs/nixos/modules/services/desktops/flatpak.nix14
-rw-r--r--nixpkgs/nixos/modules/services/desktops/pipewire.nix150
-rw-r--r--nixpkgs/nixos/modules/services/desktops/profile-sync-daemon.nix4
-rw-r--r--nixpkgs/nixos/modules/services/desktops/telepathy.nix5
-rw-r--r--nixpkgs/nixos/modules/services/development/blackfire.nix65
-rw-r--r--nixpkgs/nixos/modules/services/development/blackfire.xml45
-rw-r--r--nixpkgs/nixos/modules/services/development/hoogle.nix4
-rw-r--r--nixpkgs/nixos/modules/services/games/factorio.nix11
-rw-r--r--nixpkgs/nixos/modules/services/hardware/bluetooth.nix34
-rw-r--r--nixpkgs/nixos/modules/services/hardware/fwupd.nix18
-rw-r--r--nixpkgs/nixos/modules/services/hardware/lcd.nix5
-rw-r--r--nixpkgs/nixos/modules/services/hardware/sane.nix2
-rw-r--r--nixpkgs/nixos/modules/services/hardware/thermald.nix20
-rw-r--r--nixpkgs/nixos/modules/services/hardware/throttled.nix6
-rw-r--r--nixpkgs/nixos/modules/services/hardware/tlp.nix2
-rw-r--r--nixpkgs/nixos/modules/services/hardware/trezord.nix2
-rw-r--r--nixpkgs/nixos/modules/services/hardware/udev.nix8
-rw-r--r--nixpkgs/nixos/modules/services/hardware/undervolt.nix46
-rw-r--r--nixpkgs/nixos/modules/services/logging/promtail.nix86
-rw-r--r--nixpkgs/nixos/modules/services/logging/vector.nix61
-rw-r--r--nixpkgs/nixos/modules/services/mail/dovecot.nix10
-rw-r--r--nixpkgs/nixos/modules/services/mail/freepops.nix89
-rw-r--r--nixpkgs/nixos/modules/services/mail/mailman.nix36
-rw-r--r--nixpkgs/nixos/modules/services/mail/mailman.xml39
-rw-r--r--nixpkgs/nixos/modules/services/mail/postfix.nix14
-rw-r--r--nixpkgs/nixos/modules/services/mail/roundcube.nix5
-rw-r--r--nixpkgs/nixos/modules/services/mail/rspamd.nix48
-rw-r--r--nixpkgs/nixos/modules/services/mail/sympa.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/autorandr.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/cfdyndns.nix22
-rw-r--r--nixpkgs/nixos/modules/services/misc/cgminer.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/disnix.nix12
-rw-r--r--nixpkgs/nixos/modules/services/misc/domoticz.nix51
-rw-r--r--nixpkgs/nixos/modules/services/misc/dysnomia.nix86
-rw-r--r--nixpkgs/nixos/modules/services/misc/fstrim.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/gitlab.nix59
-rw-r--r--nixpkgs/nixos/modules/services/misc/gogs.nix8
-rw-r--r--nixpkgs/nixos/modules/services/misc/home-assistant.nix6
-rw-r--r--nixpkgs/nixos/modules/services/misc/jellyfin.nix40
-rw-r--r--nixpkgs/nixos/modules/services/misc/klipper.nix59
-rw-r--r--nixpkgs/nixos/modules/services/misc/matrix-appservice-discord.nix8
-rw-r--r--nixpkgs/nixos/modules/services/misc/matrix-synapse.nix9
-rw-r--r--nixpkgs/nixos/modules/services/misc/mautrix-telegram.nix3
-rw-r--r--nixpkgs/nixos/modules/services/misc/mediatomb.nix237
-rw-r--r--nixpkgs/nixos/modules/services/misc/n8n.nix78
-rw-r--r--nixpkgs/nixos/modules/services/misc/nix-daemon.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/octoprint.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/safeeyes.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/siproxd.nix18
-rw-r--r--nixpkgs/nixos/modules/services/misc/snapper.nix10
-rw-r--r--nixpkgs/nixos/modules/services/misc/ssm-agent.nix23
-rw-r--r--nixpkgs/nixos/modules/services/misc/svnserve.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix1
-rw-r--r--nixpkgs/nixos/modules/services/misc/zookeeper.nix5
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/grafana-image-renderer.nix150
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/grafana.nix9
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/loki.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix111
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/netdata.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix223
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix26
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bird.nix46
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix28
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginxlog.nix51
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix39
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix25
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/py-air-control.nix53
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix121
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix78
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smokeping.nix60
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix104
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/smartd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/teamviewer.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/telegraf.nix58
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/ceph.nix8
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix17
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/netatalk.nix12
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix2
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/openafs/server.nix1
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/rsyncd.nix134
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/samba-wsdd.nix124
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/samba.nix14
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/xtreemfs.nix6
-rw-r--r--nixpkgs/nixos/modules/services/networking/avahi-daemon.nix5
-rw-r--r--nixpkgs/nixos/modules/services/networking/babeld.nix34
-rw-r--r--nixpkgs/nixos/modules/services/networking/blockbook-frontend.nix24
-rw-r--r--nixpkgs/nixos/modules/services/networking/cjdns.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/corerad.nix12
-rw-r--r--nixpkgs/nixos/modules/services/networking/dhcpcd.nix5
-rw-r--r--nixpkgs/nixos/modules/services/networking/dnscrypt-proxy2.nix62
-rw-r--r--nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix5
-rw-r--r--nixpkgs/nixos/modules/services/networking/dnsdist.nix24
-rw-r--r--nixpkgs/nixos/modules/services/networking/icecream/daemon.nix155
-rw-r--r--nixpkgs/nixos/modules/services/networking/icecream/scheduler.nix101
-rw-r--r--nixpkgs/nixos/modules/services/networking/kresd.nix14
-rw-r--r--nixpkgs/nixos/modules/services/networking/morty.nix16
-rw-r--r--nixpkgs/nixos/modules/services/networking/mosquitto.nix46
-rw-r--r--nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix7
-rw-r--r--nixpkgs/nixos/modules/services/networking/murmur.nix51
-rw-r--r--nixpkgs/nixos/modules/services/networking/namecoind.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/nar-serve.nix55
-rw-r--r--nixpkgs/nixos/modules/services/networking/nat.nix120
-rw-r--r--nixpkgs/nixos/modules/services/networking/networkmanager.nix6
-rw-r--r--nixpkgs/nixos/modules/services/networking/nextdns.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/nftables.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/nsd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/ntp/chrony.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/pdns-recursor.nix44
-rw-r--r--nixpkgs/nixos/modules/services/networking/powerdns.nix40
-rw-r--r--nixpkgs/nixos/modules/services/networking/privoxy.nix20
-rw-r--r--nixpkgs/nixos/modules/services/networking/prosody.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/shellhub-agent.nix91
-rw-r--r--nixpkgs/nixos/modules/services/networking/ssh/sshd.nix9
-rw-r--r--nixpkgs/nixos/modules/services/networking/sslh.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix18
-rw-r--r--nixpkgs/nixos/modules/services/networking/strongswan.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/stunnel.nix9
-rw-r--r--nixpkgs/nixos/modules/services/networking/supybot.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/tailscale.nix37
-rw-r--r--nixpkgs/nixos/modules/services/networking/tinc.nix238
-rw-r--r--nixpkgs/nixos/modules/services/networking/unbound.nix141
-rw-r--r--nixpkgs/nixos/modules/services/networking/wakeonlan.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/wasabibackend.nix2
-rw-r--r--nixpkgs/nixos/modules/services/security/fail2ban.nix4
-rw-r--r--nixpkgs/nixos/modules/services/security/oauth2_proxy.nix4
-rw-r--r--nixpkgs/nixos/modules/services/security/sshguard.nix6
-rw-r--r--nixpkgs/nixos/modules/services/security/tor.nix31
-rw-r--r--nixpkgs/nixos/modules/services/security/usbguard.nix4
-rw-r--r--nixpkgs/nixos/modules/services/security/vault.nix4
-rw-r--r--nixpkgs/nixos/modules/services/system/cloud-init.nix2
-rw-r--r--nixpkgs/nixos/modules/services/system/dbus.nix35
-rw-r--r--nixpkgs/nixos/modules/services/torrent/transmission.nix10
-rw-r--r--nixpkgs/nixos/modules/services/ttys/agetty.nix2
-rwxr-xr-xnixpkgs/nixos/modules/services/video/epgstation/generate31
-rw-r--r--nixpkgs/nixos/modules/services/video/epgstation/streaming.json126
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/engelsystem.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/frab.nix222
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/gerrit.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/grocy.nix6
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/hedgedoc.nix (renamed from nixpkgs/nixos/modules/services/web-apps/codimd.nix)117
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/keycloak.nix692
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/keycloak.xml205
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/moinmoin.nix3
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/moodle.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/nextcloud.nix81
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/plantuml-server.nix123
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/shiori.nix51
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/zabbix.nix16
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix16
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/caddy.nix37
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/molly-brown.nix21
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/nginx/default.nix48
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix28
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix7
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix7
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/traefik.nix4
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix186
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix1
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix19
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/default.nix13
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix4
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix1
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix185
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/startx.nix12
-rw-r--r--nixpkgs/nixos/modules/services/x11/redshift.nix11
-rw-r--r--nixpkgs/nixos/modules/services/x11/terminal-server.nix2
-rw-r--r--nixpkgs/nixos/modules/services/x11/window-managers/evilwm.nix4
-rw-r--r--nixpkgs/nixos/modules/services/x11/window-managers/exwm.nix14
-rw-r--r--nixpkgs/nixos/modules/services/x11/window-managers/xmonad.nix107
-rw-r--r--nixpkgs/nixos/modules/services/x11/xserver.nix45
-rw-r--r--nixpkgs/nixos/modules/system/activation/activation-script.nix38
-rw-r--r--nixpkgs/nixos/modules/system/activation/top-level.nix3
-rw-r--r--nixpkgs/nixos/modules/system/boot/grow-partition.nix6
-rw-r--r--nixpkgs/nixos/modules/system/boot/initrd-network.nix4
-rw-r--r--nixpkgs/nixos/modules/system/boot/initrd-ssh.nix7
-rw-r--r--nixpkgs/nixos/modules/system/boot/kernel.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix6
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py4
-rw-r--r--nixpkgs/nixos/modules/system/boot/luksroot.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/networkd.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/pbkdf2-sha512.c2
-rw-r--r--nixpkgs/nixos/modules/system/boot/plymouth.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/resolved.nix7
-rw-r--r--nixpkgs/nixos/modules/system/boot/shutdown.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-1-init.sh6
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-1.nix37
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-2.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd-unit-options.nix16
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd.nix38
-rw-r--r--nixpkgs/nixos/modules/tasks/auto-upgrade.nix5
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems.nix2
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix4
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/nfs.nix48
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/unionfs-fuse.nix6
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/zfs.nix9
-rw-r--r--nixpkgs/nixos/modules/tasks/lvm.nix4
-rw-r--r--nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix12
-rw-r--r--nixpkgs/nixos/modules/tasks/network-interfaces.nix20
-rw-r--r--nixpkgs/nixos/modules/testing/test-instrumentation.nix27
-rw-r--r--nixpkgs/nixos/modules/virtualisation/amazon-image.nix5
-rw-r--r--nixpkgs/nixos/modules/virtualisation/amazon-init.nix2
-rw-r--r--nixpkgs/nixos/modules/virtualisation/azure-agent.nix2
-rw-r--r--nixpkgs/nixos/modules/virtualisation/brightbox-image.nix2
-rw-r--r--nixpkgs/nixos/modules/virtualisation/docker.nix3
-rw-r--r--nixpkgs/nixos/modules/virtualisation/ec2-amis.nix21
-rw-r--r--nixpkgs/nixos/modules/virtualisation/ec2-metadata-fetcher.nix80
-rw-r--r--nixpkgs/nixos/modules/virtualisation/nixos-containers.nix28
-rw-r--r--nixpkgs/nixos/modules/virtualisation/oci-containers.nix4
-rw-r--r--nixpkgs/nixos/modules/virtualisation/openstack-config.nix2
-rw-r--r--nixpkgs/nixos/modules/virtualisation/openstack-metadata-fetcher.nix21
-rw-r--r--nixpkgs/nixos/modules/virtualisation/qemu-guest-agent.nix7
-rw-r--r--nixpkgs/nixos/modules/virtualisation/qemu-vm.nix20
-rw-r--r--nixpkgs/nixos/modules/virtualisation/vagrant-guest.nix58
-rw-r--r--nixpkgs/nixos/modules/virtualisation/vagrant-virtualbox-image.nix60
-rw-r--r--nixpkgs/nixos/modules/virtualisation/xen-dom0.nix4
307 files changed, 7750 insertions, 2666 deletions
diff --git a/nixpkgs/nixos/modules/config/console.nix b/nixpkgs/nixos/modules/config/console.nix
index f662ed62d31d..ab1667605177 100644
--- a/nixpkgs/nixos/modules/config/console.nix
+++ b/nixpkgs/nixos/modules/config/console.nix
@@ -90,20 +90,6 @@ in
       '';
     };
 
-    extraTTYs = mkOption {
-      default = [];
-      type = types.listOf types.str;
-      example = ["tty8" "tty9"];
-      description = ''
-        TTY (virtual console) devices, in addition to the consoles on
-        which mingetty and syslogd run, that must be initialised.
-        Only useful if you have some program that you want to run on
-        some fixed console.  For example, the NixOS installation CD
-        opens the manual in a web browser on console 7, so it sets
-        <option>console.extraTTYs</option> to <literal>["tty7"]</literal>.
-      '';
-    };
-
     useXkbConfig = mkOption {
       type = types.bool;
       default = false;
@@ -159,7 +145,8 @@ in
         '';
 
         systemd.services.systemd-vconsole-setup =
-          { before = [ "display-manager.service" ];
+          {
+            before = optional config.services.xserver.enable "display-manager.service";
             after = [ "systemd-udev-settle.service" ];
             restartTriggers = [ vconsoleConf consoleEnv ];
           };
@@ -199,5 +186,9 @@ in
     (mkRenamedOptionModule [ "i18n" "consoleUseXkbConfig" ] [ "console" "useXkbConfig" ])
     (mkRenamedOptionModule [ "boot" "earlyVconsoleSetup" ] [ "console" "earlySetup" ])
     (mkRenamedOptionModule [ "boot" "extraTTYs" ] [ "console" "extraTTYs" ])
+    (mkRemovedOptionModule [ "console" "extraTTYs" ] ''
+      Since NixOS switched to systemd (circa 2012), TTYs have been spawned on
+      demand, so there is no need to configure them manually.
+    '')
   ];
 }
diff --git a/nixpkgs/nixos/modules/config/fonts/fontdir.nix b/nixpkgs/nixos/modules/config/fonts/fontdir.nix
index a6aa84ae8224..c4bd3a077d33 100644
--- a/nixpkgs/nixos/modules/config/fonts/fontdir.nix
+++ b/nixpkgs/nixos/modules/config/fonts/fontdir.nix
@@ -4,15 +4,19 @@ with lib;
 
 let
 
+  cfg = config.fonts.fontDir;
+
   x11Fonts = pkgs.runCommand "X11-fonts" { preferLocalBuild = true; } ''
-    mkdir -p "$out/share/X11-fonts"
-    find ${toString config.fonts.fonts} \
-      \( -name fonts.dir -o -name '*.ttf' -o -name '*.otf' \) \
-      -exec ln -sf -t "$out/share/X11-fonts" '{}' \;
-    cd "$out/share/X11-fonts"
-    rm -f fonts.dir fonts.scale fonts.alias
-    ${pkgs.xorg.mkfontdir}/bin/mkfontdir
+    mkdir -p "$out/share/X11/fonts"
+    font_regexp='.*\.\(ttf\|ttc\|otf\|pcf\|pfa\|pfb\|bdf\)\(\.gz\)?'
+    find ${toString config.fonts.fonts} -regex "$font_regexp" \
+      -exec ln -sf -t "$out/share/X11/fonts" '{}' \;
+    cd "$out/share/X11/fonts"
+    ${optionalString cfg.decompressFonts ''
+      ${pkgs.gzip}/bin/gunzip -f *.gz
+    ''}
     ${pkgs.xorg.mkfontscale}/bin/mkfontscale
+    ${pkgs.xorg.mkfontdir}/bin/mkfontdir
     cat $(find ${pkgs.xorg.fontalias}/ -name fonts.alias) >fonts.alias
   '';
 
@@ -21,28 +25,43 @@ in
 {
 
   options = {
+    fonts.fontDir = {
 
-    fonts = {
-
-      enableFontDir = mkOption {
+      enable = mkOption {
         type = types.bool;
         default = false;
         description = ''
           Whether to create a directory with links to all fonts in
-          <filename>/run/current-system/sw/share/X11-fonts</filename>.
+          <filename>/run/current-system/sw/share/X11/fonts</filename>.
         '';
       };
 
-    };
+      decompressFonts = mkOption {
+        type = types.bool;
+        default = config.programs.xwayland.enable;
+        description = ''
+          Whether to decompress fonts in
+          <filename>/run/current-system/sw/share/X11/fonts</filename>.
+        '';
+      };
 
+    };
   };
 
-  config = mkIf config.fonts.enableFontDir {
+  config = mkIf cfg.enable {
 
+    # This is enough to make a symlink because the xserver
+    # module already links all /share/X11 paths.
     environment.systemPackages = [ x11Fonts ];
 
-    environment.pathsToLink = [ "/share/X11-fonts" ];
+    services.xserver.filesSection = ''
+      FontPath "${x11Fonts}/share/X11/fonts"
+    '';
 
   };
 
+  imports = [
+    (mkRenamedOptionModule [ "fonts" "enableFontDir" ] [ "fonts" "fontDir" "enable" ])
+  ];
+
 }
diff --git a/nixpkgs/nixos/modules/config/fonts/fonts.nix b/nixpkgs/nixos/modules/config/fonts/fonts.nix
index b9bae44b2f9c..3911196c1013 100644
--- a/nixpkgs/nixos/modules/config/fonts/fonts.nix
+++ b/nixpkgs/nixos/modules/config/fonts/fonts.nix
@@ -35,19 +35,21 @@ with lib;
   config = {
 
     fonts.fonts = mkIf config.fonts.enableDefaultFonts
-      [
-        pkgs.xorg.fontbhlucidatypewriter100dpi
-        pkgs.xorg.fontbhlucidatypewriter75dpi
+      ([
         pkgs.dejavu_fonts
         pkgs.freefont_ttf
         pkgs.gyre-fonts # TrueType substitutes for standard PostScript fonts
         pkgs.liberation_ttf
-        pkgs.xorg.fontbh100dpi
         pkgs.xorg.fontmiscmisc
         pkgs.xorg.fontcursormisc
         pkgs.unifont
         pkgs.noto-fonts-emoji
-      ];
+      ] ++ lib.optionals (config.nixpkgs.config.allowUnfree or false) [
+        # these are unfree, and will make usage with xserver fail
+        pkgs.xorg.fontbhlucidatypewriter100dpi
+        pkgs.xorg.fontbhlucidatypewriter75dpi
+        pkgs.xorg.fontbh100dpi
+      ]);
 
   };
 
diff --git a/nixpkgs/nixos/modules/config/ldap.nix b/nixpkgs/nixos/modules/config/ldap.nix
index 1a5dbcd4e26b..35813c168fd8 100644
--- a/nixpkgs/nixos/modules/config/ldap.nix
+++ b/nixpkgs/nixos/modules/config/ldap.nix
@@ -59,30 +59,28 @@ in
 
     users.ldap = {
 
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to enable authentication against an LDAP server.";
-      };
+      enable = mkEnableOption "authentication against an LDAP server";
 
       loginPam = mkOption {
         type = types.bool;
         default = true;
-        description = "Whether to include authentication against LDAP in login PAM";
+        description = "Whether to include authentication against LDAP in login PAM.";
       };
 
       nsswitch = mkOption {
         type = types.bool;
         default = true;
-        description = "Whether to include lookup against LDAP in NSS";
+        description = "Whether to include lookup against LDAP in NSS.";
       };
 
       server = mkOption {
+        type = types.str;
         example = "ldap://ldap.example.org/";
         description = "The URL of the LDAP server.";
       };
 
       base = mkOption {
+        type = types.str;
         example = "dc=example,dc=org";
         description = "The distinguished name of the search base.";
       };
@@ -129,7 +127,7 @@ in
           type = types.lines;
           description = ''
             Extra configuration options that will be added verbatim at
-            the end of the nslcd configuration file (nslcd.conf).
+            the end of the nslcd configuration file (<literal>nslcd.conf(5)</literal>).
           '' ;
         } ;
 
@@ -180,7 +178,7 @@ in
           description = ''
             Specifies the time limit (in seconds) to use when connecting
             to the directory server. This is distinct from the time limit
-            specified in <literal>users.ldap.timeLimit</literal> and affects
+            specified in <option>users.ldap.timeLimit</option> and affects
             the initial server connection only.
           '';
         };
@@ -197,7 +195,7 @@ in
             actually contact the directory server, and it is possible that
             a malformed configuration file will trigger reconnection. If
             <literal>soft</literal> is specified, then
-            <literal>nss_ldap</literal> will return immediately on server
+            <package>nss_ldap</package> will return immediately on server
             failure. All hard reconnect policies block with exponential
             backoff before retrying.
           '';
@@ -209,10 +207,10 @@ in
         type = types.lines;
         description = ''
           Extra configuration options that will be added verbatim at
-          the end of the ldap configuration file (ldap.conf).
-          If <literal>users.ldap.daemon</literal> is enabled, this
+          the end of the ldap configuration file (<literal>ldap.conf(5)</literal>).
+          If <option>users.ldap.daemon</option> is enabled, this
           configuration will not be used. In that case, use
-          <literal>users.ldap.daemon.extraConfig</literal> instead.
+          <option>users.ldap.daemon.extraConfig</option> instead.
         '' ;
       };
 
@@ -240,9 +238,9 @@ in
       '';
     };
 
-    system.nssModules = singleton (
+    system.nssModules = mkIf cfg.nsswitch (singleton (
       if cfg.daemon.enable then nss_pam_ldapd else nss_ldap
-    );
+    ));
 
     system.nssDatabases.group = optional cfg.nsswitch "ldap";
     system.nssDatabases.passwd = optional cfg.nsswitch "ldap";
@@ -276,7 +274,12 @@ in
           } >"$conf"
           mv -fT "$conf" /run/nslcd/nslcd.conf
         '';
-        restartTriggers = [ "/run/nslcd/nslcd.conf" ];
+
+        restartTriggers = [
+          nslcdConfig
+          cfg.bind.passwordFile
+          cfg.daemon.rootpwmodpwFile
+        ];
 
         serviceConfig = {
           ExecStart = "${nslcdWrapped}/bin/nslcd";
diff --git a/nixpkgs/nixos/modules/config/malloc.nix b/nixpkgs/nixos/modules/config/malloc.nix
index 31a659ee83fe..a3eb55d8a42e 100644
--- a/nixpkgs/nixos/modules/config/malloc.nix
+++ b/nixpkgs/nixos/modules/config/malloc.nix
@@ -23,7 +23,7 @@ let
     };
 
     scudo = {
-      libPath = "${pkgs.llvmPackages.compiler-rt}/lib/linux/libclang_rt.scudo-x86_64.so";
+      libPath = "${pkgs.llvmPackages_latest.compiler-rt}/lib/linux/libclang_rt.scudo-x86_64.so";
       description = ''
         A user-mode allocator based on LLVM Sanitizer’s CombinedAllocator,
         which aims at providing additional mitigations against heap based
diff --git a/nixpkgs/nixos/modules/config/no-x-libs.nix b/nixpkgs/nixos/modules/config/no-x-libs.nix
index 941ab78f8632..c3120c2bf30d 100644
--- a/nixpkgs/nixos/modules/config/no-x-libs.nix
+++ b/nixpkgs/nixos/modules/config/no-x-libs.nix
@@ -30,11 +30,12 @@ with lib;
       cairo = super.cairo.override { x11Support = false; };
       dbus = super.dbus.override { x11Support = false; };
       networkmanager-fortisslvpn = super.networkmanager-fortisslvpn.override { withGnome = false; };
+      networkmanager-iodine = super.networkmanager-iodine.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-sstp = super.networkmanager-vpnc.override { withGnome = false; };
       networkmanager-vpnc = super.networkmanager-vpnc.override { withGnome = false; };
-      networkmanager-iodine = super.networkmanager-iodine.override { withGnome = false; };
       gobject-introspection = super.gobject-introspection.override { x11Support = false; };
       qemu = super.qemu.override { gtkSupport = false; spiceSupport = false; sdlSupport = false; };
     }));
diff --git a/nixpkgs/nixos/modules/config/pulseaudio.nix b/nixpkgs/nixos/modules/config/pulseaudio.nix
index 408d0a9c33f2..a77524d75d8d 100644
--- a/nixpkgs/nixos/modules/config/pulseaudio.nix
+++ b/nixpkgs/nixos/modules/config/pulseaudio.nix
@@ -36,6 +36,8 @@ let
         ${addModuleIf cfg.zeroconf.discovery.enable "module-zeroconf-discover"}
         ${addModuleIf cfg.tcp.enable (concatStringsSep " "
            ([ "module-native-protocol-tcp" ] ++ allAnon ++ ipAnon))}
+        ${addModuleIf config.services.jack.jackd.enable "module-jack-sink"}
+        ${addModuleIf config.services.jack.jackd.enable "module-jack-source"}
         ${cfg.extraConfig}
       '';
     };
@@ -144,7 +146,9 @@ in {
 
       package = mkOption {
         type = types.package;
-        default = pkgs.pulseaudio;
+        default = if config.services.jack.jackd.enable
+                  then pkgs.pulseaudioFull
+                  else pkgs.pulseaudio;
         defaultText = "pkgs.pulseaudio";
         example = literalExample "pkgs.pulseaudioFull";
         description = ''
@@ -259,7 +263,7 @@ in {
           (drv: drv.override { pulseaudio = overriddenPackage; })
           cfg.extraModules;
         modulePaths = builtins.map
-          (drv: "${drv}/lib/pulse-${overriddenPackage.version}/modules")
+          (drv: "${drv}/${overriddenPackage.pulseDir}/modules")
           # User-provided extra modules take precedence
           (overriddenModules ++ [ overriddenPackage ]);
       in lib.concatStringsSep ":" modulePaths;
@@ -284,6 +288,8 @@ in {
             RestartSec = "500ms";
             PassEnvironment = "DISPLAY";
           };
+        } // optionalAttrs config.services.jack.jackd.enable {
+          environment.JACK_PROMISCUOUS_SERVER = "jackaudio";
         };
         sockets.pulseaudio = {
           wantedBy = [ "sockets.target" ];
diff --git a/nixpkgs/nixos/modules/config/swap.nix b/nixpkgs/nixos/modules/config/swap.nix
index adb4e2294213..4bb66e9b5144 100644
--- a/nixpkgs/nixos/modules/config/swap.nix
+++ b/nixpkgs/nixos/modules/config/swap.nix
@@ -187,7 +187,7 @@ in
             before = [ "${realDevice'}.swap" ];
             # If swap is encrypted, depending on rngd resolves a possible entropy starvation during boot
             after = mkIf (config.security.rngd.enable && sw.randomEncryption.enable) [ "rngd.service" ];
-            path = [ pkgs.utillinux ] ++ optional sw.randomEncryption.enable pkgs.cryptsetup;
+            path = [ pkgs.util-linux ] ++ optional sw.randomEncryption.enable pkgs.cryptsetup;
 
             script =
               ''
diff --git a/nixpkgs/nixos/modules/config/system-path.nix b/nixpkgs/nixos/modules/config/system-path.nix
index 67305e8499cb..27d1cef849bc 100644
--- a/nixpkgs/nixos/modules/config/system-path.nix
+++ b/nixpkgs/nixos/modules/config/system-path.nix
@@ -33,10 +33,11 @@ let
       pkgs.ncurses
       pkgs.netcat
       config.programs.ssh.package
+      pkgs.mkpasswd
       pkgs.procps
       pkgs.su
       pkgs.time
-      pkgs.utillinux
+      pkgs.util-linux
       pkgs.which
       pkgs.zstd
     ];
@@ -142,6 +143,7 @@ in
         "/share/kservices5"
         "/share/kservicetypes5"
         "/share/kxmlgui5"
+        "/share/systemd"
       ];
 
     system.path = pkgs.buildEnv {
diff --git a/nixpkgs/nixos/modules/config/update-users-groups.pl b/nixpkgs/nixos/modules/config/update-users-groups.pl
index 42f82e431954..e8421c099454 100644
--- a/nixpkgs/nixos/modules/config/update-users-groups.pl
+++ b/nixpkgs/nixos/modules/config/update-users-groups.pl
@@ -17,8 +17,7 @@ my $gidMap = -e $gidMapFile ? decode_json(read_file($gidMapFile)) : {};
 
 sub updateFile {
     my ($path, $contents, $perms) = @_;
-    write_file("$path.tmp", { binmode => ':utf8', perms => $perms // 0644 }, $contents);
-    rename("$path.tmp", $path) or die;
+    write_file($path, { atomic => 1, binmode => ':utf8', perms => $perms // 0644 }, $contents) or die;
 }
 
 
@@ -99,7 +98,7 @@ sub parseGroup {
     return ($f[0], { name => $f[0], password => $f[1], gid => $gid, members => $f[3] });
 }
 
-my %groupsCur = -f "/etc/group" ? map { parseGroup } read_file("/etc/group") : ();
+my %groupsCur = -f "/etc/group" ? map { parseGroup } read_file("/etc/group", { binmode => ":utf8" }) : ();
 
 # Read the current /etc/passwd.
 sub parseUser {
@@ -110,20 +109,19 @@ sub parseUser {
     return ($f[0], { name => $f[0], fakePassword => $f[1], uid => $uid,
         gid => $f[3], description => $f[4], home => $f[5], shell => $f[6] });
 }
-
-my %usersCur = -f "/etc/passwd" ? map { parseUser } read_file("/etc/passwd") : ();
+my %usersCur = -f "/etc/passwd" ? map { parseUser } read_file("/etc/passwd", { binmode => ":utf8" }) : ();
 
 # Read the groups that were created declaratively (i.e. not by groups)
 # in the past. These must be removed if they are no longer in the
 # current spec.
 my $declGroupsFile = "/var/lib/nixos/declarative-groups";
 my %declGroups;
-$declGroups{$_} = 1 foreach split / /, -e $declGroupsFile ? read_file($declGroupsFile) : "";
+$declGroups{$_} = 1 foreach split / /, -e $declGroupsFile ? read_file($declGroupsFile, { binmode => ":utf8" }) : "";
 
 # Idem for the users.
 my $declUsersFile = "/var/lib/nixos/declarative-users";
 my %declUsers;
-$declUsers{$_} = 1 foreach split / /, -e $declUsersFile ? read_file($declUsersFile) : "";
+$declUsers{$_} = 1 foreach split / /, -e $declUsersFile ? read_file($declUsersFile, { binmode => ":utf8" }) : "";
 
 
 # Generate a new /etc/group containing the declared groups.
@@ -176,7 +174,7 @@ foreach my $name (keys %groupsCur) {
 # Rewrite /etc/group. FIXME: acquire lock.
 my @lines = map { join(":", $_->{name}, $_->{password}, $_->{gid}, $_->{members}) . "\n" }
     (sort { $a->{gid} <=> $b->{gid} } values(%groupsOut));
-updateFile($gidMapFile, encode_json($gidMap));
+updateFile($gidMapFile, to_json($gidMap));
 updateFile("/etc/group", \@lines);
 system("nscd --invalidate group");
 
@@ -212,11 +210,12 @@ foreach my $u (@{$spec->{users}}) {
         }
     }
 
-    # Create a home directory.
+    # Ensure home directory incl. ownership and permissions.
     if ($u->{createHome}) {
         make_path(dirname($u->{home}), { mode => 0755 });
         mkdir $u->{home}, 0700 if ! -e $u->{home};
         chown $u->{uid}, $u->{gid}, $u->{home};
+        chmod 0700, $u->{home};
     }
 
     if (defined $u->{passwordFile}) {
@@ -230,6 +229,15 @@ foreach my $u (@{$spec->{users}}) {
         $u->{hashedPassword} = hashPassword($u->{password});
     }
 
+    if (!defined $u->{shell}) {
+        if (defined $existing) {
+            $u->{shell} = $existing->{shell};
+        } else {
+            warn "warning: no declarative or previous shell for ‘$name’, setting shell to nologin\n";
+            $u->{shell} = "/run/current-system/sw/bin/nologin";
+        }
+    }
+
     $u->{fakePassword} = $existing->{fakePassword} // "x";
     $usersOut{$name} = $u;
 
@@ -253,7 +261,7 @@ foreach my $name (keys %usersCur) {
 # Rewrite /etc/passwd. FIXME: acquire lock.
 @lines = map { join(":", $_->{name}, $_->{fakePassword}, $_->{uid}, $_->{gid}, $_->{description}, $_->{home}, $_->{shell}) . "\n" }
     (sort { $a->{uid} <=> $b->{uid} } (values %usersOut));
-updateFile($uidMapFile, encode_json($uidMap));
+updateFile($uidMapFile, to_json($uidMap));
 updateFile("/etc/passwd", \@lines);
 system("nscd --invalidate passwd");
 
@@ -262,7 +270,7 @@ system("nscd --invalidate passwd");
 my @shadowNew;
 my %shadowSeen;
 
-foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow") : ()) {
+foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow", { binmode => ":utf8" }) : ()) {
     chomp $line;
     my ($name, $hashedPassword, @rest) = split(':', $line, -9);
     my $u = $usersOut{$name};;
diff --git a/nixpkgs/nixos/modules/config/users-groups.nix b/nixpkgs/nixos/modules/config/users-groups.nix
index 1bb1317a8e85..e90a7d567d42 100644
--- a/nixpkgs/nixos/modules/config/users-groups.nix
+++ b/nixpkgs/nixos/modules/config/users-groups.nix
@@ -35,8 +35,7 @@ let
   '';
 
   hashedPasswordDescription = ''
-    To generate a hashed password install the <literal>mkpasswd</literal>
-    package and run <literal>mkpasswd -m sha-512</literal>.
+    To generate a hashed password run <literal>mkpasswd -m sha-512</literal>.
 
     If set to an empty string (<literal>""</literal>), this user will
     be able to log in without being asked for a password (but not via remote
@@ -139,8 +138,22 @@ let
         '';
       };
 
+      pamMount = mkOption {
+        type = with types; attrsOf str;
+        default = {};
+        description = ''
+          Attributes for user's entry in
+          <filename>pam_mount.conf.xml</filename>.
+          Useful attributes might include <code>path</code>,
+          <code>options</code>, <code>fstype</code>, and <code>server</code>.
+          See <link
+          xlink:href="http://pam-mount.sourceforge.net/pam_mount.conf.5.html" />
+          for more information.
+        '';
+      };
+
       shell = mkOption {
-        type = types.either types.shellPackage types.path;
+        type = types.nullOr (types.either types.shellPackage types.path);
         default = pkgs.shadow;
         defaultText = "pkgs.shadow";
         example = literalExample "pkgs.bashInteractive";
@@ -185,10 +198,8 @@ let
         type = types.bool;
         default = false;
         description = ''
-          If true, the home directory will be created automatically. If this
-          option is true and the home directory already exists but is not
-          owned by the user, directory owner and group will be changed to
-          match the user.
+          Whether to create the home directory and ensure ownership as well as
+          permissions to match the user.
         '';
       };
 
diff --git a/nixpkgs/nixos/modules/config/zram.nix b/nixpkgs/nixos/modules/config/zram.nix
index 5e9870bf6b1c..1f513b7e4dae 100644
--- a/nixpkgs/nixos/modules/config/zram.nix
+++ b/nixpkgs/nixos/modules/config/zram.nix
@@ -80,6 +80,15 @@ in
         '';
       };
 
+      memoryMax = mkOption {
+        default = null;
+        type = with types; nullOr int;
+        description = ''
+          Maximum total amount of memory (in bytes) that can be used by the zram
+          swap devices.
+        '';
+      };
+
       priority = mkOption {
         default = 5;
         type = types.int;
@@ -146,11 +155,16 @@ in
 
               # Calculate memory to use for zram
               mem=$(${pkgs.gawk}/bin/awk '/MemTotal: / {
-                  print int($2*${toString cfg.memoryPercent}/100.0/${toString devicesCount}*1024)
+                  value=int($2*${toString cfg.memoryPercent}/100.0/${toString devicesCount}*1024);
+                    ${lib.optionalString (cfg.memoryMax != null) ''
+                      memory_max=int(${toString cfg.memoryMax}/${toString devicesCount});
+                      if (value > memory_max) { value = memory_max }
+                    ''}
+                  print value
               }' /proc/meminfo)
 
-              ${pkgs.utillinux}/sbin/zramctl --size $mem --algorithm ${cfg.algorithm} /dev/${dev}
-              ${pkgs.utillinux}/sbin/mkswap /dev/${dev}
+              ${pkgs.util-linux}/sbin/zramctl --size $mem --algorithm ${cfg.algorithm} /dev/${dev}
+              ${pkgs.util-linux}/sbin/mkswap /dev/${dev}
             '';
             restartIfChanged = false;
           };
diff --git a/nixpkgs/nixos/modules/hardware/acpilight.nix b/nixpkgs/nixos/modules/hardware/acpilight.nix
index 34e8a2220965..2de448a265c7 100644
--- a/nixpkgs/nixos/modules/hardware/acpilight.nix
+++ b/nixpkgs/nixos/modules/hardware/acpilight.nix
@@ -19,6 +19,7 @@ in
   };
 
   config = mkIf cfg.enable {
+    environment.systemPackages = with pkgs; [ acpilight ];
     services.udev.packages = with pkgs; [ acpilight ];
   };
 }
diff --git a/nixpkgs/nixos/modules/hardware/all-firmware.nix b/nixpkgs/nixos/modules/hardware/all-firmware.nix
index b07edb0f6acd..8cf3e5633dc7 100644
--- a/nixpkgs/nixos/modules/hardware/all-firmware.nix
+++ b/nixpkgs/nixos/modules/hardware/all-firmware.nix
@@ -48,6 +48,7 @@ in {
         rtl8192su-firmware
         rt5677-firmware
         rtl8723bs-firmware
+        rtl8761b-firmware
         rtlwifi_new-firmware
         zd1211fw
         alsa-firmware
diff --git a/nixpkgs/nixos/modules/hardware/keyboard/zsa.nix b/nixpkgs/nixos/modules/hardware/keyboard/zsa.nix
new file mode 100644
index 000000000000..5cb09e5af499
--- /dev/null
+++ b/nixpkgs/nixos/modules/hardware/keyboard/zsa.nix
@@ -0,0 +1,27 @@
+{ config, lib, pkgs, ... }:
+
+let
+  inherit (lib) mkOption mkIf types;
+  cfg = config.hardware.keyboard.zsa;
+in
+{
+  # TODO: make group configurable like in https://github.com/NixOS/nixpkgs/blob/0b2b4b8c4e729535a61db56468809c5c2d3d175c/pkgs/tools/security/nitrokey-app/udev-rules.nix ?
+  options.hardware.keyboard.zsa = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enables udev rules for keyboards from ZSA like the ErgoDox EZ, Planck EZ and Moonlander Mark I.
+        You need it when you want to flash a new configuration on the keyboard
+        or use their live training in the browser.
+        Access to the keyboard is granted to users in the "plugdev" group.
+        You may want to install the wally-cli package.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.udev.packages = [ pkgs.zsa-udev-rules ];
+    users.groups.plugdev = {};
+  };
+}
diff --git a/nixpkgs/nixos/modules/hardware/opentabletdriver.nix b/nixpkgs/nixos/modules/hardware/opentabletdriver.nix
new file mode 100644
index 000000000000..b759bcf034ee
--- /dev/null
+++ b/nixpkgs/nixos/modules/hardware/opentabletdriver.nix
@@ -0,0 +1,58 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.hardware.opentabletdriver;
+in
+{
+  options = {
+    hardware.opentabletdriver = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enable OpenTabletDriver udev rules, user service and blacklist kernel
+          modules known to conflict with OpenTabletDriver.
+        '';
+      };
+
+      blacklistedKernelModules = mkOption {
+        type = types.listOf types.str;
+        default = [ "hid-uclogic" "wacom" ];
+        description = ''
+          Blacklist of kernel modules known to conflict with OpenTabletDriver.
+        '';
+      };
+
+      daemon = {
+        enable = mkOption {
+          default = true;
+          type = types.bool;
+          description = ''
+            Whether to start OpenTabletDriver daemon as a systemd user service.
+          '';
+        };
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = with pkgs; [ opentabletdriver ];
+
+    services.udev.packages = with pkgs; [ opentabletdriver ];
+
+    boot.blacklistedKernelModules = cfg.blacklistedKernelModules;
+
+    systemd.user.services.opentabletdriver = with pkgs; mkIf cfg.daemon.enable {
+      description = "Open source, cross-platform, user-mode tablet driver";
+      wantedBy = [ "graphical-session.target" ];
+      partOf = [ "graphical-session.target" ];
+
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = "${opentabletdriver}/bin/otd-daemon -c ${opentabletdriver}/lib/OpenTabletDriver/Configurations";
+        Restart = "on-failure";
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/hardware/rtl-sdr.nix b/nixpkgs/nixos/modules/hardware/rtl-sdr.nix
new file mode 100644
index 000000000000..77c8cb59a3d5
--- /dev/null
+++ b/nixpkgs/nixos/modules/hardware/rtl-sdr.nix
@@ -0,0 +1,20 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.hardware.rtl-sdr;
+
+in {
+  options.hardware.rtl-sdr = {
+    enable = lib.mkEnableOption ''
+      Enables rtl-sdr udev rules and ensures 'plugdev' group exists.
+      This is a prerequisite to using devices supported by rtl-sdr without
+      being root, since rtl-sdr USB descriptors will be owned by plugdev
+      through udev.
+    '';
+  };
+
+  config = lib.mkIf cfg.enable {
+    services.udev.packages = [ pkgs.rtl-sdr ];
+    users.groups.plugdev = {};
+  };
+}
diff --git a/nixpkgs/nixos/modules/hardware/video/nvidia.nix b/nixpkgs/nixos/modules/hardware/video/nvidia.nix
index 2acb891f1a9a..d1cf7d05c1b8 100644
--- a/nixpkgs/nixos/modules/hardware/video/nvidia.nix
+++ b/nixpkgs/nixos/modules/hardware/video/nvidia.nix
@@ -235,7 +235,7 @@ in
     hardware.opengl.extraPackages32 = optional offloadCfg.enable nvidia_libs32;
 
     environment.systemPackages = [ nvidia_x11.bin nvidia_x11.settings ]
-      ++ filter (p: p != null) [ nvidia_x11.persistenced ];
+      ++ optionals nvidiaPersistencedEnabled [ nvidia_x11.persistenced ];
 
     systemd.packages = optional cfg.powerManagement.enable nvidia_x11.out;
 
diff --git a/nixpkgs/nixos/modules/i18n/input-method/default.nix b/nixpkgs/nixos/modules/i18n/input-method/default.nix
index 9548a249efa0..0d6dd3399bfc 100644
--- a/nixpkgs/nixos/modules/i18n/input-method/default.nix
+++ b/nixpkgs/nixos/modules/i18n/input-method/default.nix
@@ -29,7 +29,7 @@ in
   options.i18n = {
     inputMethod = {
       enabled = mkOption {
-        type    = types.nullOr (types.enum [ "ibus" "fcitx" "nabi" "uim" ]);
+        type    = types.nullOr (types.enum [ "ibus" "fcitx" "nabi" "uim" "hime" ]);
         default = null;
         example = "fcitx";
         description = ''
@@ -44,6 +44,7 @@ in
           <listitem><para>fcitx: A customizable lightweight input method, extra input engines can be added using <literal>i18n.inputMethod.fcitx.engines</literal>.</para></listitem>
           <listitem><para>nabi: A Korean input method based on XIM. Nabi doesn't support Qt 5.</para></listitem>
           <listitem><para>uim: The universal input method, is a library with a XIM bridge. uim mainly support Chinese, Japanese and Korean.</para></listitem>
+          <listitem><para>hime: An extremely easy-to-use input method framework.</para></listitem>
           </itemizedlist>
         '';
       };
diff --git a/nixpkgs/nixos/modules/i18n/input-method/default.xml b/nixpkgs/nixos/modules/i18n/input-method/default.xml
index 117482fb0d57..73911059f8a6 100644
--- a/nixpkgs/nixos/modules/i18n/input-method/default.xml
+++ b/nixpkgs/nixos/modules/i18n/input-method/default.xml
@@ -35,6 +35,11 @@
     Uim: The universal input method, is a library with a XIM bridge.
    </para>
   </listitem>
+  <listitem>
+   <para>
+    Hime: An extremely easy-to-use input method framework.
+   </para>
+  </listitem>
  </itemizedlist>
  <section xml:id="module-services-input-methods-ibus">
   <title>IBus</title>
@@ -241,4 +246,24 @@ i18n.inputMethod = {
    used to choose uim toolbar.
   </para>
  </section>
+ <section xml:id="module-services-input-methods-hime">
+  <title>Hime</title>
+
+  <para>
+   Hime is an extremely easy-to-use input method framework. It is lightweight,
+   stable, powerful and supports many commonly used input methods, including
+   Cangjie, Zhuyin, Dayi, Rank, Shrimp, Greek, Korean Pinyin, Latin Alphabet,
+   etc...
+  </para>
+
+  <para>
+   The following snippet can be used to configure Hime:
+  </para>
+
+<programlisting>
+i18n.inputMethod = {
+  <link linkend="opt-i18n.inputMethod.enabled">enabled</link> = "hime";
+};
+</programlisting>
+ </section>
 </chapter>
diff --git a/nixpkgs/nixos/modules/i18n/input-method/hime.nix b/nixpkgs/nixos/modules/i18n/input-method/hime.nix
new file mode 100644
index 000000000000..8482130db3e3
--- /dev/null
+++ b/nixpkgs/nixos/modules/i18n/input-method/hime.nix
@@ -0,0 +1,14 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+{
+  config = mkIf (config.i18n.inputMethod.enabled == "hime") {
+    i18n.inputMethod.package = pkgs.hime;
+    environment.variables = {
+      GTK_IM_MODULE = "hime";
+      QT_IM_MODULE  = "hime";
+      XMODIFIERS    = "@im=hime";
+    };
+    services.xserver.displayManager.sessionCommands = "${pkgs.hime}/bin/hime &";
+  };
+}
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix b/nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
index 8c98691116dc..803bae4212ef 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
@@ -9,7 +9,14 @@ with lib;
 
   isoImage.edition = "gnome";
 
-  services.xserver.desktopManager.gnome3.enable = true;
+  services.xserver.desktopManager.gnome3 = {
+    # Add firefox to favorite-apps
+    favoriteAppsOverride = ''
+      [org.gnome.shell]
+      favorite-apps=[ 'firefox.desktop', 'org.gnome.Geary.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Photos.desktop', 'org.gnome.Nautilus.desktop' ]
+    '';
+    enable = true;
+  };
 
   services.xserver.displayManager = {
     gdm = {
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/iso-image.nix b/nixpkgs/nixos/modules/installer/cd-dvd/iso-image.nix
index 405fbfa10dbf..43d20a556f8d 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -143,6 +143,13 @@ let
     LINUX /boot/${config.system.boot.loader.kernelFile}
     APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7
     INITRD /boot/${config.system.boot.loader.initrdFile}
+
+    # A variant to boot with a serial console enabled
+    LABEL boot-serial
+    MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (serial console=ttyS0,115200n8)
+    LINUX /boot/${config.system.boot.loader.kernelFile}
+    APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} console=ttyS0,115200n8
+    INITRD /boot/${config.system.boot.loader.initrdFile}
   '';
 
   isolinuxMemtest86Entry = ''
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix b/nixpkgs/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
index bef6cd2fb5a2..e4ec2d6240d0 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
@@ -17,8 +17,7 @@
   # The serial ports listed here are:
   # - ttyS0: for Tegra (Jetson TX1)
   # - ttyAMA0: for QEMU's -machine virt
-  # Also increase the amount of CMA to ensure the virtual console on the RPi3 works.
-  boot.kernelParams = ["cma=32M" "console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"];
+  boot.kernelParams = ["console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"];
 
   boot.initrd.availableKernelModules = [
     # Allows early (earlier) modesetting for the Raspberry Pi
@@ -30,13 +29,25 @@
   sdImage = {
     populateFirmwareCommands = let
       configTxt = pkgs.writeText "config.txt" ''
+        [pi3]
         kernel=u-boot-rpi3.bin
 
+        [pi4]
+        kernel=u-boot-rpi4.bin
+        enable_gic=1
+        armstub=armstub8-gic.bin
+
+        # Otherwise the resolution will be weird in most cases, compared to
+        # what the pi3 firmware does by default.
+        disable_overscan=1
+
+        [all]
         # Boot in 64-bit mode.
-        arm_control=0x200
+        arm_64bit=1
 
-        # U-Boot used to need this to work, regardless of whether UART is actually used or not.
-        # TODO: check when/if this can be removed.
+        # U-Boot needs this to work, regardless of whether UART is actually used or not.
+        # Look in arch/arm/mach-bcm283x/Kconfig in the U-Boot tree to see if this is still
+        # a requirement in the future.
         enable_uart=1
 
         # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
@@ -45,8 +56,17 @@
       '';
       in ''
         (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/firmware/)
-        cp ${pkgs.ubootRaspberryPi3_64bit}/u-boot.bin firmware/u-boot-rpi3.bin
+
+        # Add the config
         cp ${configTxt} firmware/config.txt
+
+        # Add pi3 specific files
+        cp ${pkgs.ubootRaspberryPi3_64bit}/u-boot.bin firmware/u-boot-rpi3.bin
+
+        # Add pi4 specific files
+        cp ${pkgs.ubootRaspberryPi4_64bit}/u-boot.bin firmware/u-boot-rpi4.bin
+        cp ${pkgs.raspberrypi-armstubs}/armstub8-gic.bin firmware/armstub8-gic.bin
+        cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-4-b.dtb firmware/
       '';
     populateRootCommands = ''
       mkdir -p ./files/boot
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/sd-image-raspberrypi4.nix b/nixpkgs/nixos/modules/installer/cd-dvd/sd-image-raspberrypi4.nix
index 87545e842030..5bdec7de86e8 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/sd-image-raspberrypi4.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/sd-image-raspberrypi4.nix
@@ -3,36 +3,6 @@
 { config, lib, pkgs, ... }:
 
 {
-  imports = [
-    ../../profiles/base.nix
-    ../../profiles/installation-device.nix
-    ./sd-image.nix
-  ];
-
-  boot.loader.grub.enable = false;
-  boot.loader.raspberryPi.enable = true;
-  boot.loader.raspberryPi.version = 4;
+  imports = [ ./sd-image-aarch64.nix ];
   boot.kernelPackages = pkgs.linuxPackages_rpi4;
-
-  boot.consoleLogLevel = lib.mkDefault 7;
-
-  sdImage = {
-    firmwareSize = 128;
-    firmwarePartitionName = "NIXOS_BOOT";
-    # This is a hack to avoid replicating config.txt from boot.loader.raspberryPi
-    populateFirmwareCommands =
-      "${config.system.build.installBootLoader} ${config.system.build.toplevel} -d ./firmware";
-    # As the boot process is done entirely in the firmware partition.
-    populateRootCommands = "";
-  };
-
-  fileSystems."/boot/firmware" = {
-    # This effectively "renames" the attrsOf entry set in sd-image.nix
-    mountPoint = "/boot";
-    neededForBoot = true;
-  };
-
-  # the installation media is also the installation target,
-  # so we don't want to provide the installation configuration.nix.
-  installer.cloneConfig = false;
 }
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/sd-image.nix b/nixpkgs/nixos/modules/installer/cd-dvd/sd-image.nix
index 231c7bf0a6c2..b811ae07eb03 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/sd-image.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/sd-image.nix
@@ -147,10 +147,10 @@ in
     sdImage.storePaths = [ config.system.build.toplevel ];
 
     system.build.sdImage = pkgs.callPackage ({ stdenv, dosfstools, e2fsprogs,
-    mtools, libfaketime, utillinux, zstd }: stdenv.mkDerivation {
+    mtools, libfaketime, util-linux, zstd }: stdenv.mkDerivation {
       name = config.sdImage.imageName;
 
-      nativeBuildInputs = [ dosfstools e2fsprogs mtools libfaketime utillinux zstd ];
+      nativeBuildInputs = [ dosfstools e2fsprogs mtools libfaketime util-linux zstd ];
 
       inherit (config.sdImage) compressImage;
 
@@ -221,11 +221,12 @@ in
         set -euo pipefail
         set -x
         # Figure out device names for the boot device and root filesystem.
-        rootPart=$(${pkgs.utillinux}/bin/findmnt -n -o SOURCE /)
+        rootPart=$(${pkgs.util-linux}/bin/findmnt -n -o SOURCE /)
         bootDevice=$(lsblk -npo PKNAME $rootPart)
+        partNum=$(lsblk -npo MAJ:MIN $rootPart | ${pkgs.gawk}/bin/awk -F: '{print $2}')
 
         # Resize the root partition and the filesystem to fit the disk
-        echo ",+," | sfdisk -N2 --no-reread $bootDevice
+        echo ",+," | sfdisk -N$partNum --no-reread $bootDevice
         ${pkgs.parted}/bin/partprobe
         ${pkgs.e2fsprogs}/bin/resize2fs $rootPart
 
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
index 8408f56f94f9..0e67ae7de698 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix
@@ -96,7 +96,7 @@ in
 
   boot.initrd.extraUtilsCommands =
     ''
-      copy_bin_and_libs ${pkgs.utillinux}/sbin/hwclock
+      copy_bin_and_libs ${pkgs.util-linux}/sbin/hwclock
     '';
 
   boot.initrd.postDeviceCommands =
diff --git a/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix
index a15a2dbadb8c..6b1f54beee2e 100644
--- a/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix
+++ b/nixpkgs/nixos/modules/installer/tools/nix-fallback-paths.nix
@@ -1,6 +1,6 @@
 {
-  x86_64-linux = "/nix/store/4vz8sh9ngx34ivi0bw5hlycxdhvy5hvz-nix-2.3.7";
-  i686-linux = "/nix/store/dzxkg9lpp60bjmzvagns42vqlz3yq5kx-nix-2.3.7";
-  aarch64-linux = "/nix/store/cfvf8nl8mwyw817by5y8zd3s8pnf5m9f-nix-2.3.7";
-  x86_64-darwin = "/nix/store/5ira7xgs92inqz1x8l0n1wci4r79hnd0-nix-2.3.7";
+  x86_64-linux = "/nix/store/iwfs2bfcy7lqwhri94p2i6jc87ih55zk-nix-2.3.10";
+  i686-linux = "/nix/store/a3ccfvy9i5n418d5v0bir330kbcz3vj8-nix-2.3.10";
+  aarch64-linux = "/nix/store/bh5g6cv7bv35iz853d3xv2sphn51ybmb-nix-2.3.10";
+  x86_64-darwin = "/nix/store/8c98r6zlwn2d40qm7jnnrr2rdlqviszr-nix-2.3.10";
 }
diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix b/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
index 0c9f8522cc12..e49ceba24245 100644
--- a/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
+++ b/nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
@@ -15,4 +15,4 @@ with import ../../../../lib/testing-python.nix {
   pkgs = import ../../../../.. { inherit system config; };
 };
 
-(makeTest { inherit nodes; testScript = ""; }).driver
+(makeTest { inherit nodes; testScript = ""; }).driverInteractive
diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-enter.sh b/nixpkgs/nixos/modules/installer/tools/nixos-enter.sh
index c72ef6e9c28b..450d77618148 100644
--- a/nixpkgs/nixos/modules/installer/tools/nixos-enter.sh
+++ b/nixpkgs/nixos/modules/installer/tools/nixos-enter.sh
@@ -69,6 +69,9 @@ mount --rbind /sys "$mountPoint/sys"
 
     # Run the activation script. Set $LOCALE_ARCHIVE to supress some Perl locale warnings.
     LOCALE_ARCHIVE="$system/sw/lib/locale/locale-archive" chroot "$mountPoint" "$system/activate" 1>&2 || true
+
+    # Create /tmp
+    chroot "$mountPoint" systemd-tmpfiles --create --remove --exclude-prefix=/dev 1>&2 || true
 )
 
 exec chroot "$mountPoint" "${command[@]}"
diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl
index c8303a6eb602..6e3ddb875e1b 100644
--- a/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -183,6 +183,11 @@ sub pciCheck {
         push @imports, "(modulesPath + \"/hardware/network/broadcom-43xx.nix\")";
     }
 
+    # In case this is a virtio scsi device, we need to explicitly make this available.
+    if ($vendor eq "0x1af4" && $device eq "0x1004") {
+        push @initrdAvailableKernelModules, "virtio_scsi";
+    }
+
     # Can't rely on $module here, since the module may not be loaded
     # due to missing firmware.  Ideally we would check modules.pcimap
     # here.
@@ -625,10 +630,14 @@ EOF
 
         my $networkingDhcpConfig = generateNetworkingDhcpConfig();
 
+        (my $desktopConfiguration = <<EOF)=~s/^/  /gm;
+@desktopConfiguration@
+EOF
+
         write_file($fn, <<EOF);
 @configuration@
 EOF
-        print STDERR "For more hardware-specific settings, see https://github.com/NixOS/nixos-hardware"
+        print STDERR "For more hardware-specific settings, see https://github.com/NixOS/nixos-hardware.\n"
     } else {
         print STDERR "warning: not overwriting existing $fn\n";
     }
diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-install.sh b/nixpkgs/nixos/modules/installer/tools/nixos-install.sh
index a180d1bc4c19..9d49d4055e43 100644
--- a/nixpkgs/nixos/modules/installer/tools/nixos-install.sh
+++ b/nixpkgs/nixos/modules/installer/tools/nixos-install.sh
@@ -64,7 +64,7 @@ while [ "$#" -gt 0 ]; do
         --no-bootloader)
             noBootLoader=1
             ;;
-        --show-trace)
+        --show-trace|--impure|--keep-going)
             extraBuildFlags+=("$i")
             ;;
         --help)
@@ -153,7 +153,7 @@ if [[ -z $system ]]; then
     else
         echo "building the flake in $flake..."
         nix "${flakeFlags[@]}" build "$flake#$flakeAttr.config.system.build.toplevel" \
-            --extra-substituters "$sub" "${verbosity[@]}" \
+            --store "$mountPoint" --extra-substituters "$sub" "${verbosity[@]}" \
             "${extraBuildFlags[@]}" "${lockFlags[@]}" --out-link "$outLink"
     fi
     system=$(readlink -f "$outLink")
diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-rebuild.sh b/nixpkgs/nixos/modules/installer/tools/nixos-rebuild.sh
index 08813d17ff99..e452e24d263d 100644
--- a/nixpkgs/nixos/modules/installer/tools/nixos-rebuild.sh
+++ b/nixpkgs/nixos/modules/installer/tools/nixos-rebuild.sh
@@ -68,7 +68,7 @@ while [ "$#" -gt 0 ]; do
         j="$1"; shift 1
         extraBuildFlags+=("$i" "$j")
         ;;
-      --show-trace|--keep-failed|-K|--keep-going|-k|--verbose|-v|-vv|-vvv|-vvvv|-vvvvv|--fallback|--repair|--no-build-output|-Q|-j*|-L|--refresh|--no-net)
+      --show-trace|--keep-failed|-K|--keep-going|-k|--verbose|-v|-vv|-vvv|-vvvv|-vvvvv|--fallback|--repair|--no-build-output|-Q|-j*|-L|--refresh|--no-net|--impure)
         extraBuildFlags+=("$i")
         ;;
       --option)
diff --git a/nixpkgs/nixos/modules/installer/tools/tools.nix b/nixpkgs/nixos/modules/installer/tools/tools.nix
index e1e1b47aafcb..0582812f92d2 100644
--- a/nixpkgs/nixos/modules/installer/tools/tools.nix
+++ b/nixpkgs/nixos/modules/installer/tools/tools.nix
@@ -23,7 +23,6 @@ let
     inherit (pkgs) runtimeShell;
     nix = config.nix.package.out;
     path = makeBinPath [
-      pkgs.nixUnstable
       pkgs.jq
       nixos-enter
     ];
@@ -46,7 +45,7 @@ let
     src = ./nixos-generate-config.pl;
     path = lib.optionals (lib.elem "btrfs" config.boot.supportedFilesystems) [ pkgs.btrfs-progs ];
     perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/${pkgs.perl.libPrefix}";
-    inherit (config.system.nixos-generate-config) configuration;
+    inherit (config.system.nixos-generate-config) configuration desktopConfiguration;
   };
 
   nixos-option =
@@ -79,24 +78,42 @@ in
 
 {
 
-  options.system.nixos-generate-config.configuration = mkOption {
-    internal = true;
-    type = types.str;
-    description = ''
-      The NixOS module that <literal>nixos-generate-config</literal>
-      saves to <literal>/etc/nixos/configuration.nix</literal>.
-
-      This is an internal option. No backward compatibility is guaranteed.
-      Use at your own risk!
+  options.system.nixos-generate-config = {
+    configuration = mkOption {
+      internal = true;
+      type = types.str;
+      description = ''
+        The NixOS module that <literal>nixos-generate-config</literal>
+        saves to <literal>/etc/nixos/configuration.nix</literal>.
+
+        This is an internal option. No backward compatibility is guaranteed.
+        Use at your own risk!
+
+        Note that this string gets spliced into a Perl script. The perl
+        variable <literal>$bootLoaderConfig</literal> can be used to
+        splice in the boot loader configuration.
+      '';
+    };
 
-      Note that this string gets spliced into a Perl script. The perl
-      variable <literal>$bootLoaderConfig</literal> can be used to
-      splice in the boot loader configuration.
-    '';
+    desktopConfiguration = mkOption {
+      internal = true;
+      type = types.str;
+      default = "";
+      description = ''
+        Text to preseed the desktop configuration that <literal>nixos-generate-config</literal>
+        saves to <literal>/etc/nixos/configuration.nix</literal>.
+
+        This is an internal option. No backward compatibility is guaranteed.
+        Use at your own risk!
+
+        Note that this string gets spliced into a Perl script. The perl
+        variable <literal>$bootLoaderConfig</literal> can be used to
+        splice in the boot loader configuration.
+      '';
+    };
   };
 
   config = {
-
     system.nixos-generate-config.configuration = mkDefault ''
       # Edit this configuration file to define what should be installed on
       # your system.  Help is available in the configuration.nix(5) man page
@@ -114,6 +131,9 @@ in
         # networking.hostName = "nixos"; # Define your hostname.
         # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.
 
+        # Set your time zone.
+        # time.timeZone = "Europe/Amsterdam";
+
       $networkingDhcpConfig
         # Configure network proxy if necessary
         # networking.proxy.default = "http://user:password\@proxy:port/";
@@ -126,13 +146,32 @@ in
         #   keyMap = "us";
         # };
 
-        # Set your time zone.
-        # time.timeZone = "Europe/Amsterdam";
+      $desktopConfiguration
+        # Configure keymap in X11
+        # services.xserver.layout = "us";
+        # services.xserver.xkbOptions = "eurosign:e";
+
+        # Enable CUPS to print documents.
+        # services.printing.enable = true;
+
+        # Enable sound.
+        # sound.enable = true;
+        # hardware.pulseaudio.enable = true;
+
+        # Enable touchpad support (enabled default in most desktopManager).
+        # services.xserver.libinput.enable = true;
+
+        # Define a user account. Don't forget to set a password with ‘passwd’.
+        # users.users.jane = {
+        #   isNormalUser = true;
+        #   extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
+        # };
 
         # List packages installed in system profile. To search, run:
         # \$ nix search wget
         # environment.systemPackages = with pkgs; [
         #   wget vim
+        #   firefox
         # ];
 
         # Some programs need SUID wrappers, can be configured further or are
@@ -141,7 +180,6 @@ in
         # programs.gnupg.agent = {
         #   enable = true;
         #   enableSSHSupport = true;
-        #   pinentryFlavor = "gnome3";
         # };
 
         # List services that you want to enable:
@@ -155,31 +193,6 @@ in
         # Or disable the firewall altogether.
         # networking.firewall.enable = false;
 
-        # Enable CUPS to print documents.
-        # services.printing.enable = true;
-
-        # Enable sound.
-        # sound.enable = true;
-        # hardware.pulseaudio.enable = true;
-
-        # Enable the X11 windowing system.
-        # services.xserver.enable = true;
-        # services.xserver.layout = "us";
-        # services.xserver.xkbOptions = "eurosign:e";
-
-        # Enable touchpad support.
-        # services.xserver.libinput.enable = true;
-
-        # Enable the KDE Desktop Environment.
-        # services.xserver.displayManager.sddm.enable = true;
-        # services.xserver.desktopManager.plasma5.enable = true;
-
-        # Define a user account. Don't forget to set a password with ‘passwd’.
-        # users.users.jane = {
-        #   isNormalUser = true;
-        #   extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
-        # };
-
         # This value determines the NixOS release from which the default
         # settings for stateful data, like file locations and database versions
         # on your system were taken. It‘s perfectly fine and recommended to leave
diff --git a/nixpkgs/nixos/modules/misc/documentation.nix b/nixpkgs/nixos/modules/misc/documentation.nix
index 71a40b4f4d6e..fe0263f158f4 100644
--- a/nixpkgs/nixos/modules/misc/documentation.nix
+++ b/nixpkgs/nixos/modules/misc/documentation.nix
@@ -40,9 +40,9 @@ let
       in scrubbedEval.options;
   };
 
-  helpScript = pkgs.writeScriptBin "nixos-help"
-    ''
-      #! ${pkgs.runtimeShell} -e
+
+  nixos-help = let
+    helpScript = pkgs.writeShellScriptBin "nixos-help" ''
       # Finds first executable browser in a colon-separated list.
       # (see how xdg-open defines BROWSER)
       browser="$(
@@ -59,14 +59,22 @@ let
       exec "$browser" ${manual.manualHTMLIndex}
     '';
 
-  desktopItem = pkgs.makeDesktopItem {
-    name = "nixos-manual";
-    desktopName = "NixOS Manual";
-    genericName = "View NixOS documentation in a web browser";
-    icon = "nix-snowflake";
-    exec = "${helpScript}/bin/nixos-help";
-    categories = "System";
-  };
+    desktopItem = pkgs.makeDesktopItem {
+      name = "nixos-manual";
+      desktopName = "NixOS Manual";
+      genericName = "View NixOS documentation in a web browser";
+      icon = "nix-snowflake";
+      exec = "nixos-help";
+      categories = "System";
+    };
+
+    in pkgs.symlinkJoin {
+      name = "nixos-help";
+      paths = [
+        helpScript
+        desktopItem
+      ];
+    };
 
 in
 
@@ -209,7 +217,7 @@ in
           manualCache = pkgs.runCommandLocal "man-cache" { }
           ''
             echo "MANDB_MAP ${manualPages}/share/man $out" > man.conf
-            ${pkgs.man-db}/bin/mandb -C man.conf -psc
+            ${pkgs.man-db}/bin/mandb -C man.conf -psc >/dev/null 2>&1
           '';
         in
         ''
@@ -250,8 +258,8 @@ in
 
       environment.systemPackages = []
         ++ optional cfg.man.enable manual.manpages
-        ++ optionals cfg.doc.enable ([ manual.manualHTML helpScript ]
-           ++ optionals config.services.xserver.enable [ desktopItem pkgs.nixos-icons ]);
+        ++ optionals cfg.doc.enable ([ manual.manualHTML nixos-help ]
+           ++ optionals config.services.xserver.enable [ pkgs.nixos-icons ]);
 
       services.mingetty.helpLine = mkIf cfg.doc.enable (
           "\nRun 'nixos-help' for the NixOS manual."
diff --git a/nixpkgs/nixos/modules/misc/ids.nix b/nixpkgs/nixos/modules/misc/ids.nix
index ac9782906e1f..fd9541062969 100644
--- a/nixpkgs/nixos/modules/misc/ids.nix
+++ b/nixpkgs/nixos/modules/misc/ids.nix
@@ -135,7 +135,7 @@ in
       #keys = 96; # unused
       #haproxy = 97; # dynamically allocated as of 2020-03-11
       mongodb = 98;
-      openldap = 99;
+      #openldap = 99; # dynamically allocated as of PR#94610
       #users = 100; # unused
       cgminer = 101;
       munin = 102;
@@ -290,14 +290,14 @@ in
       hound = 259;
       leaps = 260;
       ipfs  = 261;
-      stanchion = 262;
-      riak-cs = 263;
+      # stanchion = 262; # unused, removed 2020-10-14
+      # riak-cs = 263; # unused, removed 2020-10-14
       infinoted = 264;
       sickbeard = 265;
       headphones = 266;
       couchpotato = 267;
       gogs = 268;
-      pdns-recursor = 269;
+      #pdns-recursor = 269; # dynamically allocated as of 2020-20-18
       #kresd = 270; # switched to "knot-resolver" with dynamic ID
       rpc = 271;
       geoip = 272;
@@ -451,7 +451,7 @@ in
       keys = 96;
       #haproxy = 97; # dynamically allocated as of 2020-03-11
       #mongodb = 98; # unused
-      openldap = 99;
+      #openldap = 99; # dynamically allocated as of PR#94610
       munin = 102;
       #logcheck = 103; # unused
       #nix-ssh = 104; # unused
@@ -468,7 +468,7 @@ in
       #minecraft = 114; # unused
       vault = 115;
       #ripped = 116; # unused
-      #murmur = 117; # unused
+      murmur = 117;
       foundationdb = 118;
       newrelic = 119;
       starbound = 120;
@@ -593,8 +593,8 @@ in
       hound = 259;
       leaps = 260;
       ipfs = 261;
-      stanchion = 262;
-      riak-cs = 263;
+      # stanchion = 262; # unused, removed 2020-10-14
+      # riak-cs = 263; # unused, removed 2020-10-14
       infinoted = 264;
       sickbeard = 265;
       headphones = 266;
diff --git a/nixpkgs/nixos/modules/misc/locate.nix b/nixpkgs/nixos/modules/misc/locate.nix
index 92aa3be0a366..426281c94129 100644
--- a/nixpkgs/nixos/modules/misc/locate.nix
+++ b/nixpkgs/nixos/modules/misc/locate.nix
@@ -73,7 +73,72 @@ in {
 
     pruneFS = mkOption {
       type = listOf str;
-      default = ["afs" "anon_inodefs" "auto" "autofs" "bdev" "binfmt" "binfmt_misc" "cgroup" "cifs" "coda" "configfs" "cramfs" "cpuset" "debugfs" "devfs" "devpts" "devtmpfs" "ecryptfs" "eventpollfs" "exofs" "futexfs" "ftpfs" "fuse" "fusectl" "gfs" "gfs2" "hostfs" "hugetlbfs" "inotifyfs" "iso9660" "jffs2" "lustre" "misc" "mqueue" "ncpfs" "nnpfs" "ocfs" "ocfs2" "pipefs" "proc" "ramfs" "rpc_pipefs" "securityfs" "selinuxfs" "sfs" "shfs" "smbfs" "sockfs" "spufs" "nfs" "NFS" "nfs4" "nfsd" "sshfs" "subfs" "supermount" "sysfs" "tmpfs" "ubifs" "udf" "usbfs" "vboxsf" "vperfctrfs" ];
+      default = [
+        "afs"
+        "anon_inodefs"
+        "auto"
+        "autofs"
+        "bdev"
+        "binfmt"
+        "binfmt_misc"
+        "cgroup"
+        "cifs"
+        "coda"
+        "configfs"
+        "cramfs"
+        "cpuset"
+        "debugfs"
+        "devfs"
+        "devpts"
+        "devtmpfs"
+        "ecryptfs"
+        "eventpollfs"
+        "exofs"
+        "futexfs"
+        "ftpfs"
+        "fuse"
+        "fusectl"
+        "fuse.sshfs"
+        "gfs"
+        "gfs2"
+        "hostfs"
+        "hugetlbfs"
+        "inotifyfs"
+        "iso9660"
+        "jffs2"
+        "lustre"
+        "misc"
+        "mqueue"
+        "ncpfs"
+        "nnpfs"
+        "ocfs"
+        "ocfs2"
+        "pipefs"
+        "proc"
+        "ramfs"
+        "rpc_pipefs"
+        "securityfs"
+        "selinuxfs"
+        "sfs"
+        "shfs"
+        "smbfs"
+        "sockfs"
+        "spufs"
+        "nfs"
+        "NFS"
+        "nfs4"
+        "nfsd"
+        "sshfs"
+        "subfs"
+        "supermount"
+        "sysfs"
+        "tmpfs"
+        "ubifs"
+        "udf"
+        "usbfs"
+        "vboxsf"
+        "vperfctrfs"
+      ];
       description = ''
         Which filesystem types to exclude from indexing
       '';
diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix
index e7a375d69b09..5e9ee2b91ab2 100644
--- a/nixpkgs/nixos/modules/module-list.nix
+++ b/nixpkgs/nixos/modules/module-list.nix
@@ -47,6 +47,7 @@
   ./hardware/digitalbitbox.nix
   ./hardware/device-tree.nix
   ./hardware/sensor/iio.nix
+  ./hardware/keyboard/zsa.nix
   ./hardware/ksm.nix
   ./hardware/ledger.nix
   ./hardware/logitech.nix
@@ -59,11 +60,13 @@
   ./hardware/pcmcia.nix
   ./hardware/printers.nix
   ./hardware/raid/hpsa.nix
+  ./hardware/rtl-sdr.nix
   ./hardware/steam-hardware.nix
   ./hardware/system-76.nix
   ./hardware/tuxedo-keyboard.nix
   ./hardware/usb-wwan.nix
   ./hardware/onlykey.nix
+  ./hardware/opentabletdriver.nix
   ./hardware/wooting.nix
   ./hardware/uinput.nix
   ./hardware/video/amdgpu.nix
@@ -79,6 +82,7 @@
   ./hardware/xpadneo.nix
   ./i18n/input-method/default.nix
   ./i18n/input-method/fcitx.nix
+  ./i18n/input-method/hime.nix
   ./i18n/input-method/ibus.nix
   ./i18n/input-method/nabi.nix
   ./i18n/input-method/uim.nix
@@ -138,12 +142,15 @@
   ./programs/light.nix
   ./programs/mosh.nix
   ./programs/mininet.nix
+  ./programs/msmtp.nix
   ./programs/mtr.nix
   ./programs/nano.nix
+  ./programs/neovim.nix
   ./programs/nm-applet.nix
   ./programs/npm.nix
   ./programs/oblogout.nix
   ./programs/plotinus.nix
+  ./programs/proxychains.nix
   ./programs/qt5ct.nix
   ./programs/screen.nix
   ./programs/sedutil.nix
@@ -170,10 +177,12 @@
   ./programs/wavemon.nix
   ./programs/waybar.nix
   ./programs/wireshark.nix
+  ./programs/wshowkeys.nix
   ./programs/x2goserver.nix
   ./programs/xfs_quota.nix
   ./programs/xonsh.nix
   ./programs/xss-lock.nix
+  ./programs/xwayland.nix
   ./programs/yabar.nix
   ./programs/zmap.nix
   ./programs/zsh/oh-my-zsh.nix
@@ -291,8 +300,6 @@
   ./services/databases/postgresql.nix
   ./services/databases/redis.nix
   ./services/databases/riak.nix
-  ./services/databases/riak-cs.nix
-  ./services/databases/stanchion.nix
   ./services/databases/victoriametrics.nix
   ./services/databases/virtuoso.nix
   ./services/desktops/accountsservice.nix
@@ -330,6 +337,7 @@
   ./services/desktops/tumbler.nix
   ./services/desktops/zeitgeist.nix
   ./services/development/bloop.nix
+  ./services/development/blackfire.nix
   ./services/development/hoogle.nix
   ./services/development/jupyter/default.nix
   ./services/development/jupyterhub/default.nix
@@ -389,16 +397,17 @@
   ./services/logging/logcheck.nix
   ./services/logging/logrotate.nix
   ./services/logging/logstash.nix
+  ./services/logging/promtail.nix
   ./services/logging/rsyslogd.nix
   ./services/logging/syslog-ng.nix
   ./services/logging/syslogd.nix
+  ./services/logging/vector.nix
   ./services/mail/clamsmtp.nix
   ./services/mail/davmail.nix
   ./services/mail/dkimproxy-out.nix
   ./services/mail/dovecot.nix
   ./services/mail/dspam.nix
   ./services/mail/exim.nix
-  ./services/mail/freepops.nix
   ./services/mail/mail.nix
   ./services/mail/mailcatcher.nix
   ./services/mail/mailhog.nix
@@ -441,6 +450,7 @@
   ./services/misc/dysnomia.nix
   ./services/misc/disnix.nix
   ./services/misc/docker-registry.nix
+  ./services/misc/domoticz.nix
   ./services/misc/errbot.nix
   ./services/misc/etcd.nix
   ./services/misc/ethminer.nix
@@ -465,6 +475,7 @@
   ./services/misc/irkerd.nix
   ./services/misc/jackett.nix
   ./services/misc/jellyfin.nix
+  ./services/misc/klipper.nix
   ./services/misc/logkeys.nix
   ./services/misc/leaps.nix
   ./services/misc/lidarr.nix
@@ -476,6 +487,7 @@
   ./services/misc/mediatomb.nix
   ./services/misc/metabase.nix
   ./services/misc/mwlib.nix
+  ./services/misc/n8n.nix
   ./services/misc/nix-daemon.nix
   ./services/misc/nix-gc.nix
   ./services/misc/nix-optimise.nix
@@ -530,6 +542,7 @@
   ./services/monitoring/do-agent.nix
   ./services/monitoring/fusion-inventory.nix
   ./services/monitoring/grafana.nix
+  ./services/monitoring/grafana-image-renderer.nix
   ./services/monitoring/grafana-reporter.nix
   ./services/monitoring/graphite.nix
   ./services/monitoring/hdaps.nix
@@ -538,6 +551,7 @@
   ./services/monitoring/kapacitor.nix
   ./services/monitoring/loki.nix
   ./services/monitoring/longview.nix
+  ./services/monitoring/mackerel-agent.nix
   ./services/monitoring/monit.nix
   ./services/monitoring/munin.nix
   ./services/monitoring/nagios.nix
@@ -578,6 +592,7 @@
   ./services/network-filesystems/orangefs/client.nix
   ./services/network-filesystems/rsyncd.nix
   ./services/network-filesystems/samba.nix
+  ./services/network-filesystems/samba-wsdd.nix
   ./services/network-filesystems/tahoe.nix
   ./services/network-filesystems/diod.nix
   ./services/network-filesystems/u9fs.nix
@@ -645,6 +660,8 @@
   ./services/networking/hylafax/default.nix
   ./services/networking/i2pd.nix
   ./services/networking/i2p.nix
+  ./services/networking/icecream/scheduler.nix
+  ./services/networking/icecream/daemon.nix
   ./services/networking/iodine.nix
   ./services/networking/iperf3.nix
   ./services/networking/ircd-hybrid/default.nix
@@ -676,6 +693,7 @@
   ./services/networking/murmur.nix
   ./services/networking/mxisd.nix
   ./services/networking/namecoind.nix
+  ./services/networking/nar-serve.nix
   ./services/networking/nat.nix
   ./services/networking/ndppd.nix
   ./services/networking/networkmanager.nix
@@ -730,6 +748,7 @@
   ./services/networking/skydns.nix
   ./services/networking/shadowsocks.nix
   ./services/networking/shairport-sync.nix
+  ./services/networking/shellhub-agent.nix
   ./services/networking/shorewall.nix
   ./services/networking/shorewall6.nix
   ./services/networking/shout.nix
@@ -844,21 +863,21 @@
   ./services/web-apps/atlassian/confluence.nix
   ./services/web-apps/atlassian/crowd.nix
   ./services/web-apps/atlassian/jira.nix
-  ./services/web-apps/codimd.nix
   ./services/web-apps/convos.nix
   ./services/web-apps/cryptpad.nix
   ./services/web-apps/documize.nix
   ./services/web-apps/dokuwiki.nix
   ./services/web-apps/engelsystem.nix
-  ./services/web-apps/frab.nix
   ./services/web-apps/gerrit.nix
   ./services/web-apps/gotify-server.nix
   ./services/web-apps/grocy.nix
+  ./services/web-apps/hedgedoc.nix
   ./services/web-apps/icingaweb2/icingaweb2.nix
   ./services/web-apps/icingaweb2/module-monitoring.nix
   ./services/web-apps/ihatemoney
   ./services/web-apps/jirafeau.nix
   ./services/web-apps/jitsi-meet.nix
+  ./services/web-apps/keycloak.nix
   ./services/web-apps/limesurvey.nix
   ./services/web-apps/mattermost.nix
   ./services/web-apps/mediawiki.nix
@@ -866,6 +885,7 @@
   ./services/web-apps/moodle.nix
   ./services/web-apps/nextcloud.nix
   ./services/web-apps/nexus.nix
+  ./services/web-apps/plantuml-server.nix
   ./services/web-apps/pgpkeyserver-lite.nix
   ./services/web-apps/matomo.nix
   ./services/web-apps/moinmoin.nix
diff --git a/nixpkgs/nixos/modules/profiles/hardened.nix b/nixpkgs/nixos/modules/profiles/hardened.nix
index 7bff79e82730..680fa40b9119 100644
--- a/nixpkgs/nixos/modules/profiles/hardened.nix
+++ b/nixpkgs/nixos/modules/profiles/hardened.nix
@@ -1,5 +1,10 @@
 # A profile with most (vanilla) hardening options enabled by default,
-# potentially at the cost of features and performance.
+# potentially at the cost of stability, features and performance.
+#
+# This profile enables options that are known to affect system
+# stability. If you experience any stability issues when using the
+# profile, try disabling it. If you report an issue and use this
+# profile, always mention that you do.
 
 { config, lib, pkgs, ... }:
 
@@ -67,6 +72,8 @@ with lib;
     "jfs"
     "minix"
     "nilfs2"
+    "ntfs"
+    "omfs"
     "qnx4"
     "qnx6"
     "sysv"
diff --git a/nixpkgs/nixos/modules/programs/bandwhich.nix b/nixpkgs/nixos/modules/programs/bandwhich.nix
index 5413044f4614..1cffb5fa2765 100644
--- a/nixpkgs/nixos/modules/programs/bandwhich.nix
+++ b/nixpkgs/nixos/modules/programs/bandwhich.nix
@@ -4,7 +4,7 @@ with lib;
 
 let cfg = config.programs.bandwhich;
 in {
-  meta.maintainers = with maintainers; [ filalex77 ];
+  meta.maintainers = with maintainers; [ Br1ght0ne ];
 
   options = {
     programs.bandwhich = {
diff --git a/nixpkgs/nixos/modules/programs/chromium.nix b/nixpkgs/nixos/modules/programs/chromium.nix
index 3f0429136190..b727f850a949 100644
--- a/nixpkgs/nixos/modules/programs/chromium.nix
+++ b/nixpkgs/nixos/modules/programs/chromium.nix
@@ -29,7 +29,7 @@ in
           page. To install a chromium extension not included in the chrome web
           store, append to the extension id a semicolon ";" followed by a URL
           pointing to an Update Manifest XML file. See
-          <link xlink:href="https://www.chromium.org/administrators/policy-list-3#ExtensionInstallForcelist">ExtensionInstallForcelist</link>
+          <link xlink:href="https://cloud.google.com/docs/chrome-enterprise/policies/?policy=ExtensionInstallForcelist">ExtensionInstallForcelist</link>
           for additional details.
         '';
         default = [];
diff --git a/nixpkgs/nixos/modules/programs/command-not-found/command-not-found.pl b/nixpkgs/nixos/modules/programs/command-not-found/command-not-found.pl
index ab7aa204653c..7515dd975c31 100644
--- a/nixpkgs/nixos/modules/programs/command-not-found/command-not-found.pl
+++ b/nixpkgs/nixos/modules/programs/command-not-found/command-not-found.pl
@@ -27,8 +27,8 @@ if (!defined $res || scalar @$res == 0) {
     my $package = @$res[0]->{package};
     if ($ENV{"NIX_AUTO_INSTALL"} // "") {
         print STDERR <<EOF;
-The program ‘$program’ is currently not installed. It is provided by
-the package ‘$package’, which I will now install for you.
+The program '$program' is currently not installed. It is provided by
+the package '$package', which I will now install for you.
 EOF
         ;
         exit 126 if system("nix-env", "-iA", "nixos.$package") == 0;
@@ -36,16 +36,17 @@ EOF
         exec("nix-shell", "-p", $package, "--run", shell_quote("exec", @ARGV));
     } else {
         print STDERR <<EOF;
-The program ‘$program’ is currently not installed. You can install it by typing:
-  nix-env -iA nixos.$package
+The program '$program' is not in your PATH. You can make it available in an
+ephemeral shell by typing:
+  nix-shell -p $package
 EOF
     }
 } else {
     print STDERR <<EOF;
-The program ‘$program’ is currently not installed. It is provided by
-several packages. You can install it by typing one of the following:
+The program '$program' is not in your PATH. It is provided by several packages.
+You can make it available in an ephemeral shell by typing one of the following:
 EOF
-    print STDERR "  nix-env -iA nixos.$_->{package}\n" foreach @$res;
+    print STDERR "  nix-shell -p $_->{package}\n" foreach @$res;
 }
 
 exit 127;
diff --git a/nixpkgs/nixos/modules/programs/firejail.nix b/nixpkgs/nixos/modules/programs/firejail.nix
index 484f9eb44406..ad4ef1a39459 100644
--- a/nixpkgs/nixos/modules/programs/firejail.nix
+++ b/nixpkgs/nixos/modules/programs/firejail.nix
@@ -11,10 +11,20 @@ let
     }
     ''
       mkdir -p $out/bin
-      ${lib.concatStringsSep "\n" (lib.mapAttrsToList (command: binary: ''
+      ${lib.concatStringsSep "\n" (lib.mapAttrsToList (command: value:
+      let
+        opts = if builtins.isAttrs value
+        then value
+        else { executable = value; profile = null; extraArgs = []; };
+        args = lib.escapeShellArgs (
+          (optional (opts.profile != null) "--profile=${toString opts.profile}")
+          ++ opts.extraArgs
+          );
+      in
+      ''
         cat <<_EOF >$out/bin/${command}
         #! ${pkgs.runtimeShell} -e
-        exec /run/wrappers/bin/firejail ${binary} "\$@"
+        exec /run/wrappers/bin/firejail ${args} -- ${toString opts.executable} "\$@"
         _EOF
         chmod 0755 $out/bin/${command}
       '') cfg.wrappedBinaries)}
@@ -25,12 +35,38 @@ in {
     enable = mkEnableOption "firejail";
 
     wrappedBinaries = mkOption {
-      type = types.attrsOf types.path;
+      type = types.attrsOf (types.either types.path (types.submodule {
+        options = {
+          executable = mkOption {
+            type = types.path;
+            description = "Executable to run sandboxed";
+            example = literalExample "''${lib.getBin pkgs.firefox}/bin/firefox";
+          };
+          profile = mkOption {
+            type = types.nullOr types.path;
+            default = null;
+            description = "Profile to use";
+            example = literalExample "''${pkgs.firejail}/etc/firejail/firefox.profile";
+          };
+          extraArgs = mkOption {
+            type = types.listOf types.str;
+            default = [];
+            description = "Extra arguments to pass to firejail";
+            example = [ "--private=~/.firejail_home" ];
+          };
+        };
+      }));
       default = {};
       example = literalExample ''
         {
-          firefox = "''${lib.getBin pkgs.firefox}/bin/firefox";
-          mpv = "''${lib.getBin pkgs.mpv}/bin/mpv";
+          firefox = {
+            executable = "''${lib.getBin pkgs.firefox}/bin/firefox";
+            profile = "''${pkgs.firejail}/etc/firejail/firefox.profile";
+          };
+          mpv = {
+            executable = "''${lib.getBin pkgs.mpv}/bin/mpv";
+            profile = "''${pkgs.firejail}/etc/firejail/mpv.profile";
+          };
         }
       '';
       description = ''
diff --git a/nixpkgs/nixos/modules/programs/fish.nix b/nixpkgs/nixos/modules/programs/fish.nix
index 39b92edf2ac2..50d1077dd410 100644
--- a/nixpkgs/nixos/modules/programs/fish.nix
+++ b/nixpkgs/nixos/modules/programs/fish.nix
@@ -103,7 +103,7 @@ in
     programs.fish.shellAliases = mapAttrs (name: mkDefault) cfge.shellAliases;
 
     # Required for man completions
-    documentation.man.generateCaches = true;
+    documentation.man.generateCaches = lib.mkDefault true;
 
     environment.etc."fish/foreign-env/shellInit".text = cfge.shellInit;
     environment.etc."fish/foreign-env/loginShellInit".text = cfge.loginShellInit;
diff --git a/nixpkgs/nixos/modules/programs/msmtp.nix b/nixpkgs/nixos/modules/programs/msmtp.nix
new file mode 100644
index 000000000000..217060e6b3b3
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/msmtp.nix
@@ -0,0 +1,104 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.msmtp;
+
+in {
+  meta.maintainers = with maintainers; [ pacien ];
+
+  options = {
+    programs.msmtp = {
+      enable = mkEnableOption "msmtp - an SMTP client";
+
+      setSendmail = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to set the system sendmail to msmtp's.
+        '';
+      };
+
+      defaults = mkOption {
+        type = types.attrs;
+        default = {};
+        example = {
+          aliases = "/etc/aliases";
+          port = 587;
+          tls = true;
+        };
+        description = ''
+          Default values applied to all accounts.
+          See msmtp(1) for the available options.
+        '';
+      };
+
+      accounts = mkOption {
+        type = with types; attrsOf attrs;
+        default = {};
+        example = {
+          "default" = {
+            host = "smtp.example";
+            auth = true;
+            user = "someone";
+            passwordeval = "cat /secrets/password.txt";
+          };
+        };
+        description = ''
+          Named accounts and their respective configurations.
+          The special name "default" allows a default account to be defined.
+          See msmtp(1) for the available options.
+
+          Use `programs.msmtp.extraConfig` instead of this attribute set-based
+          option if ordered account inheritance is needed.
+
+          It is advised to use the `passwordeval` setting to read the password
+          from a secret file to avoid having it written in the world-readable
+          nix store. The password file must end with a newline (`\n`).
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra lines to add to the msmtp configuration verbatim.
+          See msmtp(1) for the syntax and available options.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.msmtp ];
+
+    services.mail.sendmailSetuidWrapper = mkIf cfg.setSendmail {
+      program = "sendmail";
+      source = "${pkgs.msmtp}/bin/sendmail";
+      setuid = false;
+      setgid = false;
+    };
+
+    environment.etc."msmtprc".text = let
+      mkValueString = v:
+        if v == true then "on"
+        else if v == false then "off"
+        else generators.mkValueStringDefault {} v;
+      mkKeyValueString = k: v: "${k} ${mkValueString v}";
+      mkInnerSectionString =
+        attrs: concatStringsSep "\n" (mapAttrsToList mkKeyValueString attrs);
+      mkAccountString = name: attrs: ''
+        account ${name}
+        ${mkInnerSectionString attrs}
+      '';
+    in ''
+      defaults
+      ${mkInnerSectionString cfg.defaults}
+
+      ${concatStringsSep "\n" (mapAttrsToList mkAccountString cfg.accounts)}
+
+      ${cfg.extraConfig}
+    '';
+  };
+}
diff --git a/nixpkgs/nixos/modules/programs/neovim.nix b/nixpkgs/nixos/modules/programs/neovim.nix
new file mode 100644
index 000000000000..0a1a2ac2b752
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/neovim.nix
@@ -0,0 +1,165 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.neovim;
+
+  runtime' = filter (f: f.enable) (attrValues cfg.runtime);
+
+  # taken from the etc module
+  runtime = pkgs.stdenvNoCC.mkDerivation {
+    name = "runtime";
+
+    builder = ../system/etc/make-etc.sh;
+
+    preferLocalBuild = true;
+    allowSubstitutes = false;
+
+    sources = map (x: x.source) runtime';
+    targets = map (x: x.target) runtime';
+  };
+
+in {
+  options.programs.neovim = {
+    enable = mkEnableOption "Neovim";
+
+    defaultEditor = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        When enabled, installs neovim and configures neovim to be the default editor
+        using the EDITOR environment variable.
+      '';
+    };
+
+    viAlias = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Symlink <command>vi</command> to <command>nvim</command> binary.
+      '';
+    };
+
+    vimAlias = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Symlink <command>vim</command> to <command>nvim</command> binary.
+      '';
+    };
+
+    withRuby = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Enable ruby provider.";
+    };
+
+    configure = mkOption {
+      type = types.attrs;
+      default = {};
+      example = literalExample ''
+        configure = {
+            customRC = $''''
+            " here your custom configuration goes!
+            $'''';
+            packages.myVimPackage = with pkgs.vimPlugins; {
+              # loaded on launch
+              start = [ fugitive ];
+              # manually loadable by calling `:packadd $plugin-name`
+              opt = [ ];
+            };
+          };
+      '';
+      description = ''
+        Generate your init file from your list of plugins and custom commands.
+        Neovim will then be wrapped to load <command>nvim -u /nix/store/<replaceable>hash</replaceable>-vimrc</command>
+      '';
+    };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.neovim-unwrapped;
+      defaultText = literalExample "pkgs.neovim-unwrapped";
+      description = "The package to use for the neovim binary.";
+    };
+
+    finalPackage = mkOption {
+      type = types.package;
+      visible = false;
+      readOnly = true;
+      description = "Resulting customized neovim package.";
+    };
+
+    runtime = mkOption {
+      default = {};
+      example = literalExample ''
+        runtime."ftplugin/c.vim".text = "setlocal omnifunc=v:lua.vim.lsp.omnifunc";
+      '';
+      description = ''
+        Set of files that have to be linked in <filename>runtime</filename>.
+      '';
+
+      type = with types; attrsOf (submodule (
+        { name, config, ... }:
+        { options = {
+
+            enable = mkOption {
+              type = types.bool;
+              default = true;
+              description = ''
+                Whether this /etc file should be generated.  This
+                option allows specific /etc files to be disabled.
+              '';
+            };
+
+            target = mkOption {
+              type = types.str;
+              description = ''
+                Name of symlink.  Defaults to the attribute
+                name.
+              '';
+            };
+
+            text = mkOption {
+              default = null;
+              type = types.nullOr types.lines;
+              description = "Text of the file.";
+            };
+
+            source = mkOption {
+              type = types.path;
+              description = "Path of the source file.";
+            };
+
+          };
+
+          config = {
+            target = mkDefault name;
+            source = mkIf (config.text != null) (
+              let name' = "neovim-runtime" + baseNameOf name;
+              in mkDefault (pkgs.writeText name' config.text));
+          };
+
+        }));
+
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [
+      cfg.finalPackage
+    ];
+    environment.variables = { EDITOR = mkOverride 900 "nvim"; };
+
+    programs.neovim.finalPackage = pkgs.wrapNeovim cfg.package {
+      inherit (cfg) viAlias vimAlias;
+      configure = cfg.configure // {
+
+        customRC = (cfg.configure.customRC or "") + ''
+          set runtimepath^=${runtime}/etc
+        '';
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/programs/proxychains.nix b/nixpkgs/nixos/modules/programs/proxychains.nix
new file mode 100644
index 000000000000..7743f79c1c0a
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/proxychains.nix
@@ -0,0 +1,165 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+
+  cfg = config.programs.proxychains;
+
+  configFile = ''
+    ${cfg.chain.type}_chain
+    ${optionalString (cfg.chain.type == "random")
+    "chain_len = ${builtins.toString cfg.chain.length}"}
+    ${optionalString cfg.proxyDNS "proxy_dns"}
+    ${optionalString cfg.quietMode "quiet_mode"}
+    remote_dns_subnet ${builtins.toString cfg.remoteDNSSubnet}
+    tcp_read_time_out ${builtins.toString cfg.tcpReadTimeOut}
+    tcp_connect_time_out ${builtins.toString cfg.tcpConnectTimeOut}
+    localnet ${cfg.localnet}
+    [ProxyList]
+    ${builtins.concatStringsSep "\n"
+      (lib.mapAttrsToList (k: v: "${v.type} ${v.host} ${builtins.toString v.port}")
+        (lib.filterAttrs (k: v: v.enable) cfg.proxies))}
+  '';
+
+  proxyOptions = {
+    options = {
+      enable = mkEnableOption "this proxy";
+
+      type = mkOption {
+        type = types.enum [ "http" "socks4" "socks5" ];
+        description = "Proxy type.";
+      };
+
+      host = mkOption {
+        type = types.str;
+        description = "Proxy host or IP address.";
+      };
+
+      port = mkOption {
+        type = types.port;
+        description = "Proxy port";
+      };
+    };
+  };
+
+in {
+
+  ###### interface
+
+  options = {
+
+    programs.proxychains = {
+
+      enable = mkEnableOption "installing proxychains configuration";
+
+      chain = {
+        type = mkOption {
+          type = types.enum [ "dynamic" "strict" "random" ];
+          default = "strict";
+          description = ''
+            <literal>dynamic</literal> - Each connection will be done via chained proxies
+            all proxies chained in the order as they appear in the list
+            at least one proxy must be online to play in chain
+            (dead proxies are skipped)
+            otherwise <literal>EINTR</literal> is returned to the app.
+
+            <literal>strict</literal> - Each connection will be done via chained proxies
+            all proxies chained in the order as they appear in the list
+            all proxies must be online to play in chain
+            otherwise <literal>EINTR</literal> is returned to the app.
+
+            <literal>random</literal> - Each connection will be done via random proxy
+            (or proxy chain, see <option>programs.proxychains.chain.length</option>) from the list.
+          '';
+        };
+        length = mkOption {
+          type = types.nullOr types.int;
+          default = null;
+          description = ''
+            Chain length for random chain.
+          '';
+        };
+      };
+
+      proxyDNS = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Proxy DNS requests - no leak for DNS data.";
+      };
+
+      quietMode = mkEnableOption "Quiet mode (no output from the library).";
+
+      remoteDNSSubnet = mkOption {
+        type = types.enum [ 10 127 224 ];
+        default = 224;
+        description = ''
+          Set the class A subnet number to use for the internal remote DNS mapping, uses the reserved 224.x.x.x range by default.
+        '';
+      };
+
+      tcpReadTimeOut = mkOption {
+        type = types.int;
+        default = 15000;
+        description = "Connection read time-out in milliseconds.";
+      };
+
+      tcpConnectTimeOut = mkOption {
+        type = types.int;
+        default = 8000;
+        description = "Connection time-out in milliseconds.";
+      };
+
+      localnet = mkOption {
+        type = types.str;
+        default = "127.0.0.0/255.0.0.0";
+        description = "By default enable localnet for loopback address ranges.";
+      };
+
+      proxies = mkOption {
+        type = types.attrsOf (types.submodule proxyOptions);
+        description = ''
+          Proxies to be used by proxychains.
+        '';
+
+        example = literalExample ''
+          { myproxy =
+            { type = "socks4";
+              host = "127.0.0.1";
+              port = 1337;
+            };
+          }
+        '';
+      };
+
+    };
+
+  };
+
+  ###### implementation
+
+  meta.maintainers = with maintainers; [ sorki ];
+
+  config = mkIf cfg.enable {
+
+    assertions = singleton {
+      assertion = cfg.chain.type != "random" && cfg.chain.length == null;
+      message = ''
+        Option `programs.proxychains.chain.length`
+        only makes sense with `programs.proxychains.chain.type` = "random".
+      '';
+    };
+
+    programs.proxychains.proxies = mkIf config.services.tor.client.enable
+      {
+        torproxy = mkDefault {
+          enable = true;
+          type = "socks4";
+          host = "127.0.0.1";
+          port = 9050;
+        };
+      };
+
+    environment.etc."proxychains.conf".text = configFile;
+    environment.systemPackages = [ pkgs.proxychains ];
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/programs/ssmtp.nix b/nixpkgs/nixos/modules/programs/ssmtp.nix
index 15d2750c193f..8039763faccc 100644
--- a/nixpkgs/nixos/modules/programs/ssmtp.nix
+++ b/nixpkgs/nixos/modules/programs/ssmtp.nix
@@ -1,6 +1,6 @@
 # Configuration for `ssmtp', a trivial mail transfer agent that can
 # replace sendmail/postfix on simple systems.  It delivers email
-# directly to an SMTP server defined in its configuration file, wihout
+# directly to an SMTP server defined in its configuration file, without
 # queueing mail locally.
 
 { config, lib, pkgs, ... }:
@@ -142,6 +142,13 @@ in
 
   config = mkIf cfg.enable {
 
+    assertions = [
+      {
+        assertion = cfg.useSTARTTLS -> cfg.useTLS;
+        message = "services.ssmtp.useSTARTTLS has no effect without services.ssmtp.useTLS";
+      }
+    ];
+
     services.ssmtp.settings = mkMerge [
       ({
         MailHub = cfg.hostName;
@@ -155,15 +162,16 @@ in
       (mkIf (cfg.authPassFile != null) { AuthPassFile = cfg.authPassFile; })
     ];
 
-    environment.etc."ssmtp/ssmtp.conf".source =
-      let
-        toStr = value:
+    # careful here: ssmtp REQUIRES all config lines to end with a newline char!
+    environment.etc."ssmtp/ssmtp.conf".text = with generators; toKeyValue {
+      mkKeyValue = mkKeyValueDefault {
+        mkValueString = value:
           if value == true then "YES"
           else if value == false then "NO"
-          else builtins.toString value
+          else mkValueStringDefault {} value
         ;
-      in
-        pkgs.writeText "ssmtp.conf" (concatStringsSep "\n" (mapAttrsToList (key: value: "${key}=${toStr value}") cfg.settings));
+      } "=";
+    } cfg.settings;
 
     environment.systemPackages = [pkgs.ssmtp];
 
diff --git a/nixpkgs/nixos/modules/programs/sway.nix b/nixpkgs/nixos/modules/programs/sway.nix
index 364debddb0f1..038d76c6c921 100644
--- a/nixpkgs/nixos/modules/programs/sway.nix
+++ b/nixpkgs/nixos/modules/programs/sway.nix
@@ -86,8 +86,7 @@ in {
     extraPackages = mkOption {
       type = with types; listOf package;
       default = with pkgs; [
-        swaylock swayidle
-        xwayland alacritty dmenu
+        swaylock swayidle alacritty dmenu
         rxvt-unicode # For backward compatibility (old default terminal)
       ];
       defaultText = literalExample ''
@@ -104,6 +103,7 @@ in {
         Extra packages to be installed system wide.
       '';
     };
+
   };
 
   config = mkIf cfg.enable {
@@ -130,6 +130,7 @@ in {
     programs.dconf.enable = mkDefault true;
     # To make a Sway session available if a display manager like SDDM is enabled:
     services.xserver.displayManager.sessionPackages = [ swayPackage ];
+    programs.xwayland.enable = mkDefault true;
   };
 
   meta.maintainers = with lib.maintainers; [ gnidorah primeos colemickens ];
diff --git a/nixpkgs/nixos/modules/programs/vim.nix b/nixpkgs/nixos/modules/programs/vim.nix
index fe0e7f2c6d6b..9f46dff2a293 100644
--- a/nixpkgs/nixos/modules/programs/vim.nix
+++ b/nixpkgs/nixos/modules/programs/vim.nix
@@ -14,10 +14,20 @@ in {
         using the EDITOR environment variable.
       '';
     };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.vim;
+      defaultText = "pkgs.vim";
+      example = "pkgs.vimHugeX";
+      description = ''
+        vim package to use.
+      '';
+    };
   };
 
   config = mkIf cfg.defaultEditor {
-        environment.systemPackages = [ pkgs.vim ];
-        environment.variables = { EDITOR = mkOverride 900 "vim"; };
+    environment.systemPackages = [ cfg.package ];
+    environment.variables = { EDITOR = mkOverride 900 "vim"; };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/wshowkeys.nix b/nixpkgs/nixos/modules/programs/wshowkeys.nix
new file mode 100644
index 000000000000..09b008af1d5d
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/wshowkeys.nix
@@ -0,0 +1,22 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.wshowkeys;
+in {
+  meta.maintainers = with maintainers; [ primeos ];
+
+  options = {
+    programs.wshowkeys = {
+      enable = mkEnableOption ''
+        wshowkeys (displays keypresses on screen on supported Wayland
+        compositors). It requires root permissions to read input events, but
+        these permissions are dropped after startup'';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    security.wrappers.wshowkeys.source = "${pkgs.wshowkeys}/bin/wshowkeys";
+  };
+}
diff --git a/nixpkgs/nixos/modules/programs/x2goserver.nix b/nixpkgs/nixos/modules/programs/x2goserver.nix
index 7d74231e956b..05707a56542f 100644
--- a/nixpkgs/nixos/modules/programs/x2goserver.nix
+++ b/nixpkgs/nixos/modules/programs/x2goserver.nix
@@ -110,7 +110,7 @@ in {
       "L+ /usr/local/bin/chmod - - - - ${coreutils}/bin/chmod"
       "L+ /usr/local/bin/cp - - - - ${coreutils}/bin/cp"
       "L+ /usr/local/bin/sed - - - - ${gnused}/bin/sed"
-      "L+ /usr/local/bin/setsid - - - - ${utillinux}/bin/setsid"
+      "L+ /usr/local/bin/setsid - - - - ${util-linux}/bin/setsid"
       "L+ /usr/local/bin/xrandr - - - - ${xorg.xrandr}/bin/xrandr"
       "L+ /usr/local/bin/xmodmap - - - - ${xorg.xmodmap}/bin/xmodmap"
     ];
diff --git a/nixpkgs/nixos/modules/programs/xwayland.nix b/nixpkgs/nixos/modules/programs/xwayland.nix
new file mode 100644
index 000000000000..7e9a424a7150
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/xwayland.nix
@@ -0,0 +1,45 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.xwayland;
+
+in
+
+{
+  options.programs.xwayland = {
+
+    enable = mkEnableOption ''
+      Xwayland X server allows running X programs on a Wayland compositor.
+    '';
+
+    defaultFontPath = mkOption {
+      type = types.str;
+      default = optionalString config.fonts.fontDir.enable
+        "/run/current-system/sw/share/X11/fonts";
+      description = ''
+        Default font path. Setting this option causes Xwayland to be rebuilt.
+      '';
+    };
+
+    package = mkOption {
+      type = types.path;
+      description = "The Xwayland package";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    # Needed by some applications for fonts and default settings
+    environment.pathsToLink = [ "/share/X11" ];
+
+    environment.systemPackages = [ cfg.package ];
+
+    programs.xwayland.package = pkgs.xwayland.override (oldArgs: {
+      inherit (cfg) defaultFontPath;
+    });
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/rename.nix b/nixpkgs/nixos/modules/rename.nix
index a87db475e012..c6f705bb2d6c 100644
--- a/nixpkgs/nixos/modules/rename.nix
+++ b/nixpkgs/nixos/modules/rename.nix
@@ -32,6 +32,7 @@ with lib;
     (mkRemovedOptionModule ["services" "cgmanager" "enable"] "cgmanager was deprecated by lxc and therefore removed from nixpkgs.")
     (mkRemovedOptionModule [ "services" "osquery" ] "The osquery module has been removed")
     (mkRemovedOptionModule [ "services" "fourStore" ] "The fourStore module has been removed")
+    (mkRemovedOptionModule [ "services" "frab" ] "The frab module has been removed")
     (mkRemovedOptionModule [ "services" "fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed")
     (mkRemovedOptionModule [ "services" "mathics" ] "The Mathics module has been removed")
     (mkRemovedOptionModule [ "programs" "way-cooler" ] ("way-cooler is abandoned by its author: " +
diff --git a/nixpkgs/nixos/modules/security/acme.nix b/nixpkgs/nixos/modules/security/acme.nix
index 8e67d4ff8716..8e646ae1567e 100644
--- a/nixpkgs/nixos/modules/security/acme.nix
+++ b/nixpkgs/nixos/modules/security/acme.nix
@@ -63,7 +63,7 @@ let
     script = with builtins; concatStringsSep "\n" (mapAttrsToList (cert: data: ''
       for fixpath in /var/lib/acme/${escapeShellArg cert} /var/lib/acme/.lego/${escapeShellArg cert}; do
         if [ -d "$fixpath" ]; then
-          chmod -R 750 "$fixpath"
+          chmod -R u=rwX,g=rX,o= "$fixpath"
           chown -R acme:${data.group} "$fixpath"
         fi
       done
@@ -104,12 +104,13 @@ let
     mkHash = with builtins; val: substring 0 20 (hashString "sha256" val);
     certDir = mkHash hashData;
     domainHash = mkHash "${concatStringsSep " " extraDomains} ${data.domain}";
-    othersHash = mkHash "${toString acmeServer} ${data.keyType}";
+    othersHash = mkHash "${toString acmeServer} ${data.keyType} ${data.email}";
     accountDir = "/var/lib/acme/.lego/accounts/" + othersHash;
 
     protocolOpts = if useDns then (
       [ "--dns" data.dnsProvider ]
       ++ optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ]
+      ++ optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ]
     ) else (
       [ "--http" "--http.webroot" data.webroot ]
     );
@@ -121,19 +122,22 @@ let
       "--email" data.email
       "--key-type" data.keyType
     ] ++ protocolOpts
-      ++ optionals data.ocspMustStaple [ "--must-staple" ]
       ++ optionals (acmeServer != null) [ "--server" acmeServer ]
       ++ concatMap (name: [ "-d" name ]) extraDomains
       ++ data.extraLegoFlags;
 
+    # Although --must-staple is common to both modes, it is not declared as a
+    # mode-agnostic argument in lego and thus must come after the mode.
     runOpts = escapeShellArgs (
       commonOpts
       ++ [ "run" ]
+      ++ optionals data.ocspMustStaple [ "--must-staple" ]
       ++ data.extraLegoRunFlags
     );
     renewOpts = escapeShellArgs (
       commonOpts
       ++ [ "renew" "--reuse-key" ]
+      ++ optionals data.ocspMustStaple [ "--must-staple" ]
       ++ data.extraLegoRenewFlags
     );
 
@@ -207,7 +211,7 @@ let
 
     renewService = {
       description = "Renew ACME certificate for ${cert}";
-      after = [ "network.target" "network-online.target" "acme-fixperms.service" ] ++ selfsignedDeps;
+      after = [ "network.target" "network-online.target" "acme-fixperms.service" "nss-lookup.target" ] ++ selfsignedDeps;
       wants = [ "network-online.target" "acme-fixperms.service" ] ++ selfsignedDeps;
 
       # https://github.com/NixOS/nixpkgs/pull/81371#issuecomment-605526099
@@ -249,7 +253,8 @@ let
         echo '${domainHash}' > domainhash.txt
 
         # Check if we can renew
-        if [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' ]; then
+        # Certificates and account credentials must exist
+        if [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' -a "$(ls -1 accounts)" ]; then
 
           # When domains are updated, there's no need to do a full
           # Lego run, but it's likely renew won't work if days is too low.
@@ -267,7 +272,7 @@ let
 
         mv domainhash.txt certificates/
         chmod 640 certificates/*
-        chmod -R 700 accounts/*
+        chmod -R u=rwX,g=,o= accounts/*
 
         # Group might change between runs, re-apply it
         chown 'acme:${data.group}' certificates/*
@@ -403,6 +408,17 @@ let
         '';
       };
 
+      dnsResolver = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "1.1.1.1:53";
+        description = ''
+          Set the resolver to use for performing recursive DNS queries. Supported:
+          host:port. The default is to use the system resolvers, or Google's DNS
+          resolvers if the system's cannot be determined.
+        '';
+      };
+
       credentialsFile = mkOption {
         type = types.path;
         description = ''
diff --git a/nixpkgs/nixos/modules/security/acme.xml b/nixpkgs/nixos/modules/security/acme.xml
index 17e94bc12fb2..f24811291728 100644
--- a/nixpkgs/nixos/modules/security/acme.xml
+++ b/nixpkgs/nixos/modules/security/acme.xml
@@ -263,4 +263,28 @@ chmod 400 /var/lib/secrets/certs.secret
    ones.
   </para>
  </section>
+ <section xml:id="module-security-acme-fix-jws">
+  <title>Fixing JWS Verification error</title>
+
+  <para>
+   It is possible that your account credentials file may become corrupt and need
+   to be regenerated. In this scenario lego will produce the error <literal>JWS verification error</literal>.
+   The solution is to simply delete the associated accounts file and
+   re-run the affected service(s).
+  </para>
+
+<programlisting>
+# Find the accounts folder for the certificate
+systemctl cat acme-example.com.service | grep -Po 'accounts/[^:]*'
+export accountdir="$(!!)"
+# Move this folder to some place else
+mv /var/lib/acme/.lego/$accountdir{,.bak}
+# Recreate the folder using systemd-tmpfiles
+systemd-tmpfiles --create
+# Get a new account and reissue certificates
+# Note: Do this for all certs that share the same account email address
+systemctl start acme-example.com.service
+</programlisting>
+
+ </section>
 </chapter>
diff --git a/nixpkgs/nixos/modules/security/apparmor.nix b/nixpkgs/nixos/modules/security/apparmor.nix
index 2ee10454fd26..cfc65b347bc6 100644
--- a/nixpkgs/nixos/modules/security/apparmor.nix
+++ b/nixpkgs/nixos/modules/security/apparmor.nix
@@ -23,17 +23,11 @@ in
          default = [];
          description = "List of packages to be added to apparmor's include path";
        };
-       parserConfig = mkOption {
-         type = types.str;
-         default = "";
-         description = "AppArmor parser configuration file content";
-       };
      };
    };
 
    config = mkIf cfg.enable {
      environment.systemPackages = [ pkgs.apparmor-utils ];
-     environment.etc."apparmor/parser.conf".text = cfg.parserConfig;
 
      boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
 
diff --git a/nixpkgs/nixos/modules/security/doas.nix b/nixpkgs/nixos/modules/security/doas.nix
index b81f2d0c2d52..27f6870aaf37 100644
--- a/nixpkgs/nixos/modules/security/doas.nix
+++ b/nixpkgs/nixos/modules/security/doas.nix
@@ -12,6 +12,7 @@ let
 
   mkOpts = rule: concatStringsSep " " [
     (optionalString rule.noPass "nopass")
+    (optionalString rule.noLog "nolog")
     (optionalString rule.persist "persist")
     (optionalString rule.keepEnv "keepenv")
     "setenv { SSH_AUTH_SOCK ${concatStringsSep " " rule.setEnv} }"
@@ -118,6 +119,16 @@ in
               '';
             };
 
+            noLog = mkOption {
+              type = with types; bool;
+              default = false;
+              description = ''
+                If <code>true</code>, successful executions will not be logged
+                to
+                <citerefentry><refentrytitle>syslogd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+              '';
+            };
+
             persist = mkOption {
               type = with types; bool;
               default = false;
diff --git a/nixpkgs/nixos/modules/security/hidepid.nix b/nixpkgs/nixos/modules/security/hidepid.nix
index 55a48ea3c9c6..4953f517e93b 100644
--- a/nixpkgs/nixos/modules/security/hidepid.nix
+++ b/nixpkgs/nixos/modules/security/hidepid.nix
@@ -23,5 +23,9 @@ with lib;
 
     boot.specialFileSystems."/proc".options = [ "hidepid=2" "gid=${toString config.ids.gids.proc}" ];
     systemd.services.systemd-logind.serviceConfig.SupplementaryGroups = [ "proc" ];
+
+    # Disable cgroupsv2, which doesn't work with hidepid.
+    # https://github.com/NixOS/nixpkgs/pull/104094#issuecomment-729996203
+    systemd.enableUnifiedCgroupHierarchy = false;
   };
 }
diff --git a/nixpkgs/nixos/modules/security/pam.nix b/nixpkgs/nixos/modules/security/pam.nix
index 4141a17c5072..1522111dbddf 100644
--- a/nixpkgs/nixos/modules/security/pam.nix
+++ b/nixpkgs/nixos/modules/security/pam.nix
@@ -318,6 +318,42 @@ let
         '';
       };
 
+      gnupg = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            If enabled, pam_gnupg will attempt to automatically unlock the
+            user's GPG keys with the login password via
+            <command>gpg-agent</command>. The keygrips of all keys to be
+            unlocked should be written to <filename>~/.pam-gnupg</filename>,
+            and can be queried with <command>gpg -K --with-keygrip</command>.
+            Presetting passphrases must be enabled by adding
+            <literal>allow-preset-passphrase</literal> in
+            <filename>~/.gnupg/gpg-agent.conf</filename>.
+          '';
+        };
+
+        noAutostart = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Don't start <command>gpg-agent</command> if it is not running.
+            Useful in conjunction with starting <command>gpg-agent</command> as
+            a systemd user service.
+          '';
+        };
+
+        storeOnly = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Don't send the password immediately after login, but store for PAM
+            <literal>session</literal>.
+          '';
+        };
+      };
+
       text = mkOption {
         type = types.nullOr types.lines;
         description = "Contents of the PAM service file.";
@@ -358,15 +394,15 @@ let
           ${optionalString cfg.requireWheel
               "auth required pam_wheel.so use_uid"}
           ${optionalString cfg.logFailures
-              "auth required pam_tally.so"}
+              "auth required pam_faillock.so"}
           ${optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth)
-              "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys:~/.ssh/authorized_keys2:/etc/ssh/authorized_keys.d/%u"}
+              "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles}"}
           ${optionalString cfg.fprintAuth
               "auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so"}
           ${let p11 = config.security.pam.p11; in optionalString cfg.p11Auth
               "auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so"}
           ${let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth
-              "auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"}"}
+              "auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"}"}
           ${optionalString cfg.usbAuth
               "auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"}
           ${let oath = config.security.pam.oath; in optionalString cfg.oathAuth
@@ -386,6 +422,7 @@ let
             || cfg.enableKwallet
             || cfg.enableGnomeKeyring
             || cfg.googleAuthenticator.enable
+            || cfg.gnupg.enable
             || cfg.duoSecurity.enable)) ''
               auth required pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth
               ${optionalString config.security.pam.enableEcryptfs
@@ -397,6 +434,10 @@ let
                  " kwalletd=${pkgs.kdeFrameworks.kwallet.bin}/bin/kwalletd5")}
               ${optionalString cfg.enableGnomeKeyring
                 "auth optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so"}
+              ${optionalString cfg.gnupg.enable
+                "auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"
+                + optionalString cfg.gnupg.storeOnly " store-only"
+               }
               ${optionalString cfg.googleAuthenticator.enable
                 "auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp"}
               ${optionalString cfg.duoSecurity.enable
@@ -429,8 +470,6 @@ let
               "password sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_authtok"}
           ${optionalString config.krb5.enable
               "password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass"}
-          ${optionalString config.services.samba.syncPasswordsByPam
-              "password optional ${pkgs.samba}/lib/security/pam_smbpass.so nullok use_authtok try_first_pass"}
           ${optionalString cfg.enableGnomeKeyring
               "password optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok"}
 
@@ -474,6 +513,10 @@ let
                " kwalletd=${pkgs.kdeFrameworks.kwallet.bin}/bin/kwalletd5")}
           ${optionalString (cfg.enableGnomeKeyring)
               "session optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start"}
+          ${optionalString cfg.gnupg.enable
+              "session optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"
+              + optionalString cfg.gnupg.noAutostart " no-autostart"
+           }
           ${optionalString (config.virtualisation.lxc.lxcfs.enable)
                "session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all"}
         '');
@@ -656,6 +699,22 @@ in
         '';
       };
 
+      appId = mkOption {
+        default = null;
+        type = with types; nullOr str;
+        description = ''
+            By default <literal>pam-u2f</literal> module sets the application
+            ID to <literal>pam://$HOSTNAME</literal>.
+
+            When using <command>pamu2fcfg</command>, you can specify your
+            application ID with the <literal>-i</literal> flag.
+
+            More information can be found <link
+            xlink:href="https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html">
+            here</link>
+        '';
+      };
+
       control = mkOption {
         default = "sufficient";
         type = types.enum [ "required" "requisite" "sufficient" "optional" ];
diff --git a/nixpkgs/nixos/modules/security/pam_mount.nix b/nixpkgs/nixos/modules/security/pam_mount.nix
index 77e22a96b553..9a0143c155c5 100644
--- a/nixpkgs/nixos/modules/security/pam_mount.nix
+++ b/nixpkgs/nixos/modules/security/pam_mount.nix
@@ -39,8 +39,16 @@ in
     environment.etc."security/pam_mount.conf.xml" = {
       source =
         let
-          extraUserVolumes = filterAttrs (n: u: u.cryptHomeLuks != null) config.users.users;
-          userVolumeEntry = user: "<volume user=\"${user.name}\" path=\"${user.cryptHomeLuks}\" mountpoint=\"${user.home}\" />\n";
+          extraUserVolumes = filterAttrs (n: u: u.cryptHomeLuks != null || u.pamMount != {}) config.users.users;
+          mkAttr = k: v: ''${k}="${v}"'';
+          userVolumeEntry = user: let
+            attrs = {
+              user = user.name;
+              path = user.cryptHomeLuks;
+              mountpoint = user.home;
+            } // user.pamMount;
+          in
+            "<volume ${concatStringsSep " " (mapAttrsToList mkAttr attrs)} />\n";
         in
          pkgs.writeText "pam_mount.conf.xml" ''
           <?xml version="1.0" encoding="utf-8" ?>
@@ -52,7 +60,7 @@ in
           <!-- if activated, requires ofl from hxtools to be present -->
           <logout wait="0" hup="no" term="no" kill="no" />
           <!-- set PATH variable for pam_mount module -->
-          <path>${pkgs.utillinux}/bin</path>
+          <path>${pkgs.util-linux}/bin</path>
           <!-- create mount point if not present -->
           <mkmountpoint enable="1" remove="true" />
 
diff --git a/nixpkgs/nixos/modules/security/sudo.nix b/nixpkgs/nixos/modules/security/sudo.nix
index 1ed5269c5ae7..cc3ff3d11b91 100644
--- a/nixpkgs/nixos/modules/security/sudo.nix
+++ b/nixpkgs/nixos/modules/security/sudo.nix
@@ -42,6 +42,15 @@ in
         '';
     };
 
+    security.sudo.package = mkOption {
+      type = types.package;
+      default = pkgs.sudo;
+      defaultText = "pkgs.sudo";
+      description = ''
+        Which package to use for `sudo`.
+      '';
+    };
+
     security.sudo.wheelNeedsPassword = mkOption {
       type = types.bool;
       default = true;
@@ -208,8 +217,8 @@ in
       '';
 
     security.wrappers = {
-      sudo.source = "${pkgs.sudo.out}/bin/sudo";
-      sudoedit.source = "${pkgs.sudo.out}/bin/sudoedit";
+      sudo.source = "${cfg.package.out}/bin/sudo";
+      sudoedit.source = "${cfg.package.out}/bin/sudoedit";
     };
 
     environment.systemPackages = [ sudo ];
diff --git a/nixpkgs/nixos/modules/security/systemd-confinement.nix b/nixpkgs/nixos/modules/security/systemd-confinement.nix
index 2927d424a8a2..afb81a2b56be 100644
--- a/nixpkgs/nixos/modules/security/systemd-confinement.nix
+++ b/nixpkgs/nixos/modules/security/systemd-confinement.nix
@@ -160,7 +160,7 @@ in {
               + " the 'users.users' option instead as this combination is"
               + " currently not supported.";
     }
-    { assertion = !cfg.serviceConfig.ProtectSystem or false;
+    { assertion = cfg.serviceConfig ? ProtectSystem -> cfg.serviceConfig.ProtectSystem == false;
       message = "${whatOpt "ProtectSystem"}. ProtectSystem is not compatible"
               + " with service confinement as it fails to remount /usr within"
               + " our chroot. Please disable the option.";
diff --git a/nixpkgs/nixos/modules/security/wrappers/default.nix b/nixpkgs/nixos/modules/security/wrappers/default.nix
index 2def74f85353..de6213714ac3 100644
--- a/nixpkgs/nixos/modules/security/wrappers/default.nix
+++ b/nixpkgs/nixos/modules/security/wrappers/default.nix
@@ -163,13 +163,13 @@ in
       # These are mount related wrappers that require the +s permission.
       fusermount.source = "${pkgs.fuse}/bin/fusermount";
       fusermount3.source = "${pkgs.fuse3}/bin/fusermount3";
-      mount.source = "${lib.getBin pkgs.utillinux}/bin/mount";
-      umount.source = "${lib.getBin pkgs.utillinux}/bin/umount";
+      mount.source = "${lib.getBin pkgs.util-linux}/bin/mount";
+      umount.source = "${lib.getBin pkgs.util-linux}/bin/umount";
     };
 
     boot.specialFileSystems.${parentWrapperDir} = {
       fsType = "tmpfs";
-      options = [ "nodev" ];
+      options = [ "nodev" "mode=755" ];
     };
 
     # Make sure our wrapperDir exports to the PATH env variable when
@@ -187,6 +187,8 @@ in
           # programs to be wrapped.
           WRAPPER_PATH=${config.system.path}/bin:${config.system.path}/sbin
 
+          chmod 755 "${parentWrapperDir}"
+
           # We want to place the tmpdirs for the wrappers to the parent dir.
           wrapperDir=$(mktemp --directory --tmpdir="${parentWrapperDir}" wrappers.XXXXXXXXXX)
           chmod a+rx $wrapperDir
@@ -197,6 +199,9 @@ in
             # Atomically replace the symlink
             # See https://axialcorps.com/2013/07/03/atomically-replacing-files-and-directories/
             old=$(readlink -f ${wrapperDir})
+            if [ -e ${wrapperDir}-tmp ]; then
+              rm --force --recursive ${wrapperDir}-tmp
+            fi
             ln --symbolic --force --no-dereference $wrapperDir ${wrapperDir}-tmp
             mv --no-target-directory ${wrapperDir}-tmp ${wrapperDir}
             rm --force --recursive $old
diff --git a/nixpkgs/nixos/modules/services/admin/salt/master.nix b/nixpkgs/nixos/modules/services/admin/salt/master.nix
index c6b1b0cc0bd8..a3069c81c19a 100644
--- a/nixpkgs/nixos/modules/services/admin/salt/master.nix
+++ b/nixpkgs/nixos/modules/services/admin/salt/master.nix
@@ -45,7 +45,7 @@ in
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       path = with pkgs; [
-        utillinux  # for dmesg
+        util-linux  # for dmesg
       ];
       serviceConfig = {
         ExecStart = "${pkgs.salt}/bin/salt-master";
@@ -59,5 +59,5 @@ in
     };
   };
 
-  meta.maintainers = with lib.maintainers; [ aneeshusa ];
+  meta.maintainers = with lib.maintainers; [ Flakebi ];
 }
diff --git a/nixpkgs/nixos/modules/services/admin/salt/minion.nix b/nixpkgs/nixos/modules/services/admin/salt/minion.nix
index c8fa9461a209..ac124c570d8d 100644
--- a/nixpkgs/nixos/modules/services/admin/salt/minion.nix
+++ b/nixpkgs/nixos/modules/services/admin/salt/minion.nix
@@ -50,7 +50,7 @@ in
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       path = with pkgs; [
-        utillinux
+        util-linux
       ];
       serviceConfig = {
         ExecStart = "${pkgs.salt}/bin/salt-minion";
diff --git a/nixpkgs/nixos/modules/services/audio/jack.nix b/nixpkgs/nixos/modules/services/audio/jack.nix
index ceff366d0bbb..bee97dbfc6b3 100644
--- a/nixpkgs/nixos/modules/services/audio/jack.nix
+++ b/nixpkgs/nixos/modules/services/audio/jack.nix
@@ -246,6 +246,9 @@ in {
         description = "JACK Audio Connection Kit";
         serviceConfig = {
           User = "jackaudio";
+          SupplementaryGroups = lib.optional
+            (config.hardware.pulseaudio.enable
+            && !config.hardware.pulseaudio.systemWide) "users";
           ExecStart = "${cfg.jackd.package}/bin/jackd ${lib.escapeShellArgs cfg.jackd.extraOptions}";
           LimitRTPRIO = 99;
           LimitMEMLOCK = "infinity";
diff --git a/nixpkgs/nixos/modules/services/audio/mpd.nix b/nixpkgs/nixos/modules/services/audio/mpd.nix
index ba20b1b98d97..e09e4861646c 100644
--- a/nixpkgs/nixos/modules/services/audio/mpd.nix
+++ b/nixpkgs/nixos/modules/services/audio/mpd.nix
@@ -66,7 +66,10 @@ in {
         default = "${cfg.dataDir}/music";
         defaultText = ''''${dataDir}/music'';
         description = ''
-          The directory or NFS/SMB network share where mpd reads music from.
+          The directory or NFS/SMB network share where MPD reads music from. If left
+          as the default value this directory will automatically be created before
+          the MPD server starts, otherwise the sysadmin is responsible for ensuring
+          the directory exists with appropriate ownership and permissions.
         '';
       };
 
@@ -75,7 +78,10 @@ in {
         default = "${cfg.dataDir}/playlists";
         defaultText = ''''${dataDir}/playlists'';
         description = ''
-          The directory where mpd stores playlists.
+          The directory where MPD stores playlists. If left as the default value
+          this directory will automatically be created before the MPD server starts,
+          otherwise the sysadmin is responsible for ensuring the directory exists
+          with appropriate ownership and permissions.
         '';
       };
 
@@ -94,8 +100,10 @@ in {
         type = types.path;
         default = "/var/lib/${name}";
         description = ''
-          The directory where MPD stores its state, tag cache,
-          playlists etc.
+          The directory where MPD stores its state, tag cache, playlists etc. If
+          left as the default value this directory will automatically be created
+          before the MPD server starts, otherwise the sysadmin is responsible for
+          ensuring the directory exists with appropriate ownership and permissions.
         '';
       };
 
@@ -185,36 +193,42 @@ in {
       };
     };
 
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' - ${cfg.user} ${cfg.group} - -"
-      "d '${cfg.playlistDirectory}' - ${cfg.user} ${cfg.group} - -"
-    ];
-
     systemd.services.mpd = {
       after = [ "network.target" "sound.target" ];
       description = "Music Player Daemon";
       wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target";
 
-      serviceConfig = {
-        User = "${cfg.user}";
-        ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon /etc/mpd.conf";
-        ExecStartPre = pkgs.writeScript "mpd-start-pre" ''
-          #!${pkgs.runtimeShell}
-          set -euo pipefail
-          cat ${mpdConf} ${cfg.credentialsFile} > /etc/mpd.conf
-        '';
-        Type = "notify";
-        LimitRTPRIO = 50;
-        LimitRTTIME = "infinity";
-        ProtectSystem = true;
-        NoNewPrivileges = true;
-        ProtectKernelTunables = true;
-        ProtectControlGroups = true;
-        ProtectKernelModules = true;
-        RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK";
-        RestrictNamespaces = true;
-        Restart = "always";
-      };
+      serviceConfig = mkMerge [
+        {
+          User = "${cfg.user}";
+          ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon /etc/mpd.conf";
+          ExecStartPre = pkgs.writeScript "mpd-start-pre" ''
+            #!${pkgs.runtimeShell}
+            set -euo pipefail
+            cat ${mpdConf} ${cfg.credentialsFile} > /etc/mpd.conf
+          '';
+          Type = "notify";
+          LimitRTPRIO = 50;
+          LimitRTTIME = "infinity";
+          ProtectSystem = true;
+          NoNewPrivileges = true;
+          ProtectKernelTunables = true;
+          ProtectControlGroups = true;
+          ProtectKernelModules = true;
+          RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK";
+          RestrictNamespaces = true;
+          Restart = "always";
+        }
+        (mkIf (cfg.dataDir == "/var/lib/${name}") {
+          StateDirectory = [ name ];
+        })
+        (mkIf (cfg.playlistDirectory == "/var/lib/${name}/playlists") {
+          StateDirectory = [ name "${name}/playlists" ];
+        })
+        (mkIf (cfg.musicDirectory == "/var/lib/${name}/music") {
+          StateDirectory = [ name "${name}/music" ];
+        })
+      ];
     };
     environment.etc."mpd.conf" = {
       mode = "0640";
diff --git a/nixpkgs/nixos/modules/services/backup/syncoid.nix b/nixpkgs/nixos/modules/services/backup/syncoid.nix
index fff119c2cf00..e72e3fa59cf9 100644
--- a/nixpkgs/nixos/modules/services/backup/syncoid.nix
+++ b/nixpkgs/nixos/modules/services/backup/syncoid.nix
@@ -4,6 +4,15 @@ with lib;
 
 let
   cfg = config.services.syncoid;
+
+  # Extract pool names of local datasets (ones that don't contain "@") that
+  # have the specified type (either "source" or "target")
+  getPools = type: unique (map (d: head (builtins.match "([^/]+).*" d)) (
+    # Filter local datasets
+    filter (d: !hasInfix "@" d)
+    # Get datasets of the specified type
+    (catAttrs type (attrValues cfg.commands))
+  ));
 in {
 
     # Interface
@@ -26,14 +35,25 @@ in {
 
       user = mkOption {
         type = types.str;
-        default = "root";
+        default = "syncoid";
         example = "backup";
         description = ''
-          The user for the service. Sudo or ZFS privilege delegation must be
-          configured to use a user other than root.
+          The user for the service. ZFS privilege delegation will be
+          automatically configured for any local pools used by syncoid if this
+          option is set to a user other than root. The user will be given the
+          "hold" and "send" privileges on any pool that has datasets being sent
+          and the "create", "mount", "receive", and "rollback" privileges on
+          any pool that has datasets being received.
         '';
       };
 
+      group = mkOption {
+        type = types.str;
+        default = "syncoid";
+        example = "backup";
+        description = "The group for the service.";
+      };
+
       sshKey = mkOption {
         type = types.nullOr types.path;
         # Prevent key from being copied to store
@@ -150,6 +170,18 @@ in {
     # Implementation
 
     config = mkIf cfg.enable {
+      users =  {
+        users = mkIf (cfg.user == "syncoid") {
+          syncoid = {
+            group = cfg.group;
+            isSystemUser = true;
+          };
+        };
+        groups = mkIf (cfg.group == "syncoid") {
+          syncoid = {};
+        };
+      };
+
       systemd.services.syncoid = {
         description = "Syncoid ZFS synchronization service";
         script = concatMapStringsSep "\n" (c: lib.escapeShellArgs
@@ -160,10 +192,22 @@ in {
             ++ c.extraArgs
             ++ [ "--sendoptions" c.sendOptions
                  "--recvoptions" c.recvOptions
+                 "--no-privilege-elevation"
                  c.source c.target
                ])) (attrValues cfg.commands);
         after = [ "zfs.target" ];
-        serviceConfig.User = cfg.user;
+        serviceConfig = {
+          ExecStartPre = (map (pool: lib.escapeShellArgs [
+            "+/run/booted-system/sw/bin/zfs" "allow"
+            cfg.user "hold,send" pool
+          ]) (getPools "source")) ++
+          (map (pool: lib.escapeShellArgs [
+            "+/run/booted-system/sw/bin/zfs" "allow"
+            cfg.user "create,mount,receive,rollback" pool
+          ]) (getPools "target"));
+          User = cfg.user;
+          Group = cfg.group;
+        };
         startAt = cfg.interval;
       };
     };
diff --git a/nixpkgs/nixos/modules/services/backup/tarsnap.nix b/nixpkgs/nixos/modules/services/backup/tarsnap.nix
index 6d99a1efb613..e1200731c2ca 100644
--- a/nixpkgs/nixos/modules/services/backup/tarsnap.nix
+++ b/nixpkgs/nixos/modules/services/backup/tarsnap.nix
@@ -308,7 +308,7 @@ in
         requires    = [ "network-online.target" ];
         after       = [ "network-online.target" ];
 
-        path = with pkgs; [ iputils tarsnap utillinux ];
+        path = with pkgs; [ iputils tarsnap util-linux ];
 
         # In order for the persistent tarsnap timer to work reliably, we have to
         # make sure that the tarsnap server is reachable after systemd starts up
@@ -355,7 +355,7 @@ in
         description = "Tarsnap restore '${name}'";
         requires    = [ "network-online.target" ];
 
-        path = with pkgs; [ iputils tarsnap utillinux ];
+        path = with pkgs; [ iputils tarsnap util-linux ];
 
         script = let
           tarsnap = ''tarsnap --configfile "/etc/tarsnap/${name}.conf"'';
diff --git a/nixpkgs/nixos/modules/services/cluster/k3s/default.nix b/nixpkgs/nixos/modules/services/cluster/k3s/default.nix
index 2e8bf20a68fc..f0317fdbd160 100644
--- a/nixpkgs/nixos/modules/services/cluster/k3s/default.nix
+++ b/nixpkgs/nixos/modules/services/cluster/k3s/default.nix
@@ -76,6 +76,10 @@ in
       enable = mkDefault true;
     };
 
+    # TODO: disable this once k3s supports cgroupsv2, either by docker
+    # supporting it, or their bundled containerd
+    systemd.enableUnifiedCgroupHierarchy = false;
+
     systemd.services.k3s = {
       description = "k3s service";
       after = mkIf cfg.docker [ "docker.service" ];
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix
index c3d67552cc8c..2b6e45ba1b90 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix
@@ -241,7 +241,7 @@ in
         description = "Kubernetes Kubelet Service";
         wantedBy = [ "kubernetes.target" ];
         after = [ "network.target" "docker.service" "kube-apiserver.service" ];
-        path = with pkgs; [ gitMinimal openssh docker utillinux iproute ethtool thin-provisioning-tools iptables socat ] ++ top.path;
+        path = with pkgs; [ gitMinimal openssh docker util-linux iproute ethtool thin-provisioning-tools iptables socat ] ++ top.path;
         preStart = ''
           ${concatMapStrings (img: ''
             echo "Seeding docker image: ${img}"
diff --git a/nixpkgs/nixos/modules/services/computing/slurm/slurm.nix b/nixpkgs/nixos/modules/services/computing/slurm/slurm.nix
index 705390a21d4e..302f058926c8 100644
--- a/nixpkgs/nixos/modules/services/computing/slurm/slurm.nix
+++ b/nixpkgs/nixos/modules/services/computing/slurm/slurm.nix
@@ -34,13 +34,12 @@ let
      ${cfg.extraCgroupConfig}
    '';
 
-  slurmdbdConf = pkgs.writeTextDir "slurmdbd.conf"
+  slurmdbdConf = pkgs.writeText "slurmdbd.conf"
    ''
      DbdHost=${cfg.dbdserver.dbdHost}
      SlurmUser=${cfg.user}
      StorageType=accounting_storage/mysql
      StorageUser=${cfg.dbdserver.storageUser}
-     ${optionalString (cfg.dbdserver.storagePass != null) "StoragePass=${cfg.dbdserver.storagePass}"}
      ${cfg.dbdserver.extraConfig}
    '';
 
@@ -95,26 +94,12 @@ in
           '';
         };
 
-        storagePass = mkOption {
-          type = types.nullOr types.str;
+        storagePassFile = mkOption {
+          type = with types; nullOr str;
           default = null;
           description = ''
-            Database password. Note that this password will be publicable
-            readable in the nix store. Use <option>configFile</option>
-            to store the and config file and password outside the nix store.
-          '';
-        };
-
-        configFile = mkOption {
-          type = types.nullOr types.str;
-          default = null;
-          description = ''
-            Path to <literal>slurmdbd.conf</literal>. The password for the database connection
-            is stored in the config file. Use this option to specfify a path
-            outside the nix store. If this option is unset a configuration file
-            will be generated. See also:
-            <citerefentry><refentrytitle>slurmdbd.conf</refentrytitle>
-            <manvolnum>8</manvolnum></citerefentry>.
+            Path to file with database password. The content of this will be used to
+            create the password for the <literal>StoragePass</literal> option.
           '';
         };
 
@@ -122,7 +107,9 @@ in
           type = types.lines;
           default = "";
           description = ''
-            Extra configuration for <literal>slurmdbd.conf</literal>
+            Extra configuration for <literal>slurmdbd.conf</literal> See also:
+            <citerefentry><refentrytitle>slurmdbd.conf</refentrytitle>
+            <manvolnum>8</manvolnum></citerefentry>.
           '';
         };
       };
@@ -292,6 +279,16 @@ in
 
   };
 
+  imports = [
+    (mkRemovedOptionModule [ "services" "slurm" "dbdserver" "storagePass" ] ''
+      This option has been removed so that the database password is not exposed via the nix store.
+      Use services.slurm.dbdserver.storagePassFile to provide the database password.
+    '')
+    (mkRemovedOptionModule [ "services" "slurm" "dbdserver" "configFile" ] ''
+      This option has been removed. Use services.slurm.dbdserver.storagePassFile
+      and services.slurm.dbdserver.extraConfig instead.
+    '')
+  ];
 
   ###### implementation
 
@@ -386,23 +383,34 @@ in
       '';
     };
 
-    systemd.services.slurmdbd = mkIf (cfg.dbdserver.enable) {
+    systemd.services.slurmdbd = let
+      # slurm strips the last component off the path
+      configPath = "$RUNTIME_DIRECTORY/slurmdbd.conf";
+    in mkIf (cfg.dbdserver.enable) {
       path = with pkgs; [ wrappedSlurm munge coreutils ];
 
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" "munged.service" "mysql.service" ];
       requires = [ "munged.service" "mysql.service" ];
 
-      # slurm strips the last component off the path
-      environment.SLURM_CONF =
-        if (cfg.dbdserver.configFile == null) then
-          "${slurmdbdConf}/slurm.conf"
-        else
-          cfg.dbdserver.configFile;
+      preStart = ''
+        cp ${slurmdbdConf} ${configPath}
+        chmod 600 ${configPath}
+        chown ${cfg.user} ${configPath}
+        ${optionalString (cfg.dbdserver.storagePassFile != null) ''
+          echo "StoragePass=$(cat ${cfg.dbdserver.storagePassFile})" \
+            >> ${configPath}
+        ''}
+      '';
+
+      script = ''
+        export SLURM_CONF=${configPath}
+        exec ${cfg.package}/bin/slurmdbd -D
+      '';
 
       serviceConfig = {
-        Type = "forking";
-        ExecStart = "${cfg.package}/bin/slurmdbd";
+        RuntimeDirectory = "slurmdbd";
+        Type = "simple";
         PIDFile = "/run/slurmdbd.pid";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
       };
diff --git a/nixpkgs/nixos/modules/services/computing/torque/mom.nix b/nixpkgs/nixos/modules/services/computing/torque/mom.nix
index 0c5f43cf3e6a..6747bd4b0d5a 100644
--- a/nixpkgs/nixos/modules/services/computing/torque/mom.nix
+++ b/nixpkgs/nixos/modules/services/computing/torque/mom.nix
@@ -32,7 +32,7 @@ in
     environment.systemPackages = [ pkgs.torque ];
 
     systemd.services.torque-mom-init = {
-      path = with pkgs; [ torque utillinux procps inetutils ];
+      path = with pkgs; [ torque util-linux procps inetutils ];
 
       script = ''
         pbs_mkdirs -v aux
diff --git a/nixpkgs/nixos/modules/services/computing/torque/server.nix b/nixpkgs/nixos/modules/services/computing/torque/server.nix
index 21c5a4f46724..8d923fc04d46 100644
--- a/nixpkgs/nixos/modules/services/computing/torque/server.nix
+++ b/nixpkgs/nixos/modules/services/computing/torque/server.nix
@@ -21,7 +21,7 @@ in
     environment.systemPackages = [ pkgs.torque ];
 
     systemd.services.torque-server-init = {
-      path = with pkgs; [ torque utillinux procps inetutils ];
+      path = with pkgs; [ torque util-linux procps inetutils ];
 
       script = ''
         tmpsetup=$(mktemp -t torque-XXXX)
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixpkgs/nixos/modules/services/continuous-integration/gitlab-runner.nix
index 431555309cc9..c358a5db77c2 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/gitlab-runner.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/gitlab-runner.nix
@@ -541,7 +541,7 @@ in
         jq
         moreutils
         remarshal
-        utillinux
+        util-linux
         cfg.package
       ] ++ cfg.extraPackages;
       reloadIfChanged = true;
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix b/nixpkgs/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix
index d2e7e8e18f94..79d1ce580545 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix
@@ -25,19 +25,18 @@ in
   ];
 
   config = mkIf cfg.enable {
-
     systemd.services.hercules-ci-agent = {
       wantedBy = [ "multi-user.target" ];
       after = [ "network-online.target" ];
       wants = [ "network-online.target" ];
       path = [ config.nix.package ];
+      startLimitBurst = 30 * 1000000; # practically infinite
       serviceConfig = {
         User = "hercules-ci-agent";
         ExecStart = command;
         ExecStartPre = testCommand;
         Restart = "on-failure";
         RestartSec = 120;
-        StartLimitBurst = 30 * 1000000; # practically infinite
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix b/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix
index 502a5898a5de..252ca17006da 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -37,8 +37,6 @@ let
 
   haveLocalDB = cfg.dbi == localDB;
 
-  inherit (config.system) stateVersion;
-
   hydra-package =
   let
     makeWrapperArgs = concatStringsSep " " (mapAttrsToList (key: value: "--set \"${key}\" \"${value}\"") hydraEnv);
@@ -96,7 +94,8 @@ in
 
       package = mkOption {
         type = types.package;
-        defaultText = "pkgs.hydra";
+        default = pkgs.hydra-unstable;
+        defaultText = "pkgs.hydra-unstable";
         description = "The Hydra package.";
       };
 
@@ -225,34 +224,6 @@ in
 
   config = mkIf cfg.enable {
 
-    warnings = optional (cfg.package.migration or false) ''
-      You're currently deploying an older version of Hydra which is needed to
-      make some required database changes[1]. As soon as this is done, it's recommended
-      to run `hydra-backfill-ids` and set `services.hydra.package` to `pkgs.hydra-unstable`
-      after that.
-
-      [1] https://github.com/NixOS/hydra/pull/711
-    '';
-
-    services.hydra.package = with pkgs;
-      mkDefault (
-        if pkgs ? hydra
-          then throw ''
-            The Hydra package doesn't exist anymore in `nixpkgs`! It probably exists
-            due to an overlay. To upgrade Hydra, you need to take two steps as some
-            bigger changes in the database schema were implemented recently[1]. You first
-            need to deploy `pkgs.hydra-migration`, run `hydra-backfill-ids` on the server
-            and then deploy `pkgs.hydra-unstable`.
-
-            If you want to use `pkgs.hydra` from your overlay, please set `services.hydra.package`
-            explicitly to `pkgs.hydra` and make sure you know what you're doing.
-
-            [1] https://github.com/NixOS/hydra/pull/711
-          ''
-        else if versionOlder stateVersion "20.03" then hydra-migration
-        else hydra-unstable
-      );
-
     users.groups.hydra = {
       gid = config.ids.gids.hydra;
     };
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix
index 1477c471f8ab..cdc3b4b5c58f 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix
@@ -86,8 +86,8 @@ in {
       };
 
       packages = mkOption {
-        default = [ pkgs.stdenv pkgs.git pkgs.jdk config.programs.ssh.package pkgs.nix ];
-        defaultText = "[ pkgs.stdenv pkgs.git pkgs.jdk config.programs.ssh.package pkgs.nix ]";
+        default = [ pkgs.stdenv pkgs.git pkgs.jdk11 config.programs.ssh.package pkgs.nix ];
+        defaultText = "[ pkgs.stdenv pkgs.git pkgs.jdk11 config.programs.ssh.package pkgs.nix ]";
         type = types.listOf types.package;
         description = ''
           Packages to add to PATH for the jenkins process.
@@ -207,7 +207,7 @@ in {
 
       # For reference: https://wiki.jenkins.io/display/JENKINS/JenkinsLinuxStartupScript
       script = ''
-        ${pkgs.jdk}/bin/java ${concatStringsSep " " cfg.extraJavaOptions} -jar ${cfg.package}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \
+        ${pkgs.jdk11}/bin/java ${concatStringsSep " " cfg.extraJavaOptions} -jar ${cfg.package}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \
                                                   --httpPort=${toString cfg.port} \
                                                   --prefix=${cfg.prefix} \
                                                   -Djava.awt.headless=true \
diff --git a/nixpkgs/nixos/modules/services/databases/cassandra.nix b/nixpkgs/nixos/modules/services/databases/cassandra.nix
index 90c094f68b61..d55a7db39150 100644
--- a/nixpkgs/nixos/modules/services/databases/cassandra.nix
+++ b/nixpkgs/nixos/modules/services/databases/cassandra.nix
@@ -38,13 +38,18 @@ let
       cassandraYaml = builtins.toJSON cassandraConfigWithAddresses;
       cassandraEnvPkg = "${cfg.package}/conf/cassandra-env.sh";
       cassandraLogbackConfig = pkgs.writeText "logback.xml" cfg.logbackConfig;
+      passAsFile = [ "extraEnvSh" ];
+      inherit (cfg) extraEnvSh;
       buildCommand = ''
         mkdir -p "$out"
 
         echo "$cassandraYaml" > "$out/cassandra.yaml"
         ln -s "$cassandraLogbackConfig" "$out/logback.xml"
 
-        cp "$cassandraEnvPkg" "$out/cassandra-env.sh"
+        ( cat "$cassandraEnvPkg"
+          echo "# lines from services.cassandra.extraEnvSh: "
+          cat "$extraEnvShPath"
+        ) > "$out/cassandra-env.sh"
 
         # Delete default JMX Port, otherwise we can't set it using env variable
         sed -i '/JMX_PORT="7199"/d' "$out/cassandra-env.sh"
@@ -224,6 +229,14 @@ in {
         Extra options to be merged into cassandra.yaml as nix attribute set.
       '';
     };
+    extraEnvSh = mkOption {
+      type = types.lines;
+      default = "";
+      example = "CLASSPATH=$CLASSPATH:\${extraJar}";
+      description = ''
+        Extra shell lines to be appended onto cassandra-env.sh.
+      '';
+    };
     fullRepairInterval = mkOption {
       type = types.nullOr types.str;
       default = "3w";
diff --git a/nixpkgs/nixos/modules/services/databases/foundationdb.nix b/nixpkgs/nixos/modules/services/databases/foundationdb.nix
index 18727acc7c75..e22127403e91 100644
--- a/nixpkgs/nixos/modules/services/databases/foundationdb.nix
+++ b/nixpkgs/nixos/modules/services/databases/foundationdb.nix
@@ -233,7 +233,7 @@ in
             type = types.str;
             default = "Check.Valid=1,Check.Unexpired=1";
             description = ''
-	      "Peer verification string". This may be used to adjust which TLS
+              "Peer verification string". This may be used to adjust which TLS
               client certificates a server will accept, as a form of user
               authorization; for example, it may only accept TLS clients who
               offer a certificate abiding by some locality or organization name.
diff --git a/nixpkgs/nixos/modules/services/databases/mongodb.nix b/nixpkgs/nixos/modules/services/databases/mongodb.nix
index 4453a182990d..4af0b9d44e13 100644
--- a/nixpkgs/nixos/modules/services/databases/mongodb.nix
+++ b/nixpkgs/nixos/modules/services/databases/mongodb.nix
@@ -176,7 +176,7 @@ in
         postStart = ''
             if test -e "${cfg.dbpath}/.first_startup"; then
               ${optionalString (cfg.initialScript != null) ''
-                ${mongodb}/bin/mongo -u root -p ${cfg.initialRootPassword} admin "${cfg.initialScript}"
+                ${mongodb}/bin/mongo ${optionalString (cfg.enableAuth) "-u root -p ${cfg.initialRootPassword}"} admin "${cfg.initialScript}"
               ''}
               rm -f "${cfg.dbpath}/.first_startup"
             fi
diff --git a/nixpkgs/nixos/modules/services/databases/openldap.nix b/nixpkgs/nixos/modules/services/databases/openldap.nix
index 7472538b887e..94a5c573768b 100644
--- a/nixpkgs/nixos/modules/services/databases/openldap.nix
+++ b/nixpkgs/nixos/modules/services/databases/openldap.nix
@@ -1,43 +1,121 @@
 { config, lib, pkgs, ... }:
 
 with lib;
-
 let
-
   cfg = config.services.openldap;
+  legacyOptions = [ "rootpwFile" "suffix" "dataDir" "rootdn" "rootpw" ];
   openldap = cfg.package;
-
-  dataFile = pkgs.writeText "ldap-contents.ldif" cfg.declarativeContents;
-  configFile = pkgs.writeText "slapd.conf" ((optionalString cfg.defaultSchemas ''
-    include ${openldap.out}/etc/schema/core.schema
-    include ${openldap.out}/etc/schema/cosine.schema
-    include ${openldap.out}/etc/schema/inetorgperson.schema
-    include ${openldap.out}/etc/schema/nis.schema
-  '') + ''
-    ${cfg.extraConfig}
-    database ${cfg.database}
-    suffix ${cfg.suffix}
-    rootdn ${cfg.rootdn}
-    ${if (cfg.rootpw != null) then ''
-      rootpw ${cfg.rootpw}
-    '' else ''
-      include ${cfg.rootpwFile}
-    ''}
-    directory ${cfg.dataDir}
-    ${cfg.extraDatabaseConfig}
-  '');
-  configOpts = if cfg.configDir == null then "-f ${configFile}"
-               else "-F ${cfg.configDir}";
-in
-
-{
-
-  ###### interface
-
+  configDir = if cfg.configDir != null then cfg.configDir else "/etc/openldap/slapd.d";
+
+  ldapValueType = let
+    # Can't do types.either with multiple non-overlapping submodules, so define our own
+    singleLdapValueType = lib.mkOptionType rec {
+      name = "LDAP";
+      description = "LDAP value";
+      check = x: lib.isString x || (lib.isAttrs x && (x ? path || x ? base64));
+      merge = lib.mergeEqualOption;
+    };
+    # We don't coerce to lists of single values, as some values must be unique
+  in types.either singleLdapValueType (types.listOf singleLdapValueType);
+
+  ldapAttrsType =
+    let
+      options = {
+        attrs = mkOption {
+          type = types.attrsOf ldapValueType;
+          default = {};
+          description = "Attributes of the parent entry.";
+        };
+        children = mkOption {
+          # Hide the child attributes, to avoid infinite recursion in e.g. documentation
+          # Actual Nix evaluation is lazy, so this is not an issue there
+          type = let
+            hiddenOptions = lib.mapAttrs (name: attr: attr // { visible = false; }) options;
+          in types.attrsOf (types.submodule { options = hiddenOptions; });
+          default = {};
+          description = "Child entries of the current entry, with recursively the same structure.";
+          example = lib.literalExample ''
+            {
+                "cn=schema" = {
+                # The attribute used in the DN must be defined
+                attrs = { cn = "schema"; };
+                children = {
+                    # This entry's DN is expanded to "cn=foo,cn=schema"
+                    "cn=foo" = { ... };
+                };
+                # These includes are inserted after "cn=schema", but before "cn=foo,cn=schema"
+                includes = [ ... ];
+                };
+            }
+          '';
+        };
+        includes = mkOption {
+          type = types.listOf types.path;
+          default = [];
+          description = ''
+            LDIF files to include after the parent's attributes but before its children.
+          '';
+        };
+      };
+    in types.submodule { inherit options; };
+
+  valueToLdif = attr: values: let
+    listValues = if lib.isList values then values else lib.singleton values;
+  in map (value:
+    if lib.isAttrs value then
+      if lib.hasAttr "path" value
+      then "${attr}:< file://${value.path}"
+      else "${attr}:: ${value.base64}"
+    else "${attr}: ${lib.replaceStrings [ "\n" ] [ "\n " ] value}"
+  ) listValues;
+
+  attrsToLdif = dn: { attrs, children, includes, ... }: [''
+    dn: ${dn}
+    ${lib.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList valueToLdif attrs))}
+  ''] ++ (map (path: "include: file://${path}\n") includes) ++ (
+    lib.flatten (lib.mapAttrsToList (name: value: attrsToLdif "${name},${dn}" value) children)
+  );
+in {
+  imports = let
+    deprecationNote = "This option is removed due to the deprecation of `slapd.conf` upstream. Please migrate to `services.openldap.settings`, see the release notes for advice with this process.";
+    mkDatabaseOption = old: new:
+      lib.mkChangedOptionModule [ "services" "openldap" old ] [ "services" "openldap" "settings" "children" ]
+        (config: let
+          database = lib.getAttrFromPath [ "services" "openldap" "database" ] config;
+          value = lib.getAttrFromPath [ "services" "openldap" old ] config;
+        in lib.setAttrByPath ([ "olcDatabase={1}${database}" "attrs" ] ++ new) value);
+  in [
+    (lib.mkRemovedOptionModule [ "services" "openldap" "extraConfig" ] deprecationNote)
+    (lib.mkRemovedOptionModule [ "services" "openldap" "extraDatabaseConfig" ] deprecationNote)
+
+    (lib.mkChangedOptionModule [ "services" "openldap" "logLevel" ] [ "services" "openldap" "settings" "attrs" "olcLogLevel" ]
+      (config: lib.splitString " " (lib.getAttrFromPath [ "services" "openldap" "logLevel" ] config)))
+    (lib.mkChangedOptionModule [ "services" "openldap" "defaultSchemas" ] [ "services" "openldap" "settings" "children" "cn=schema" "includes"]
+      (config: lib.optionals (lib.getAttrFromPath [ "services" "openldap" "defaultSchemas" ] config) (
+        map (schema: "${openldap}/etc/schema/${schema}.ldif") [ "core" "cosine" "inetorgperson" "nis" ])))
+
+    (lib.mkChangedOptionModule [ "services" "openldap" "database" ] [ "services" "openldap" "settings" "children" ]
+      (config: let
+        database = lib.getAttrFromPath [ "services" "openldap" "database" ] config;
+      in {
+        "olcDatabase={1}${database}".attrs = {
+          # objectClass is case-insensitive, so don't need to capitalize ${database}
+          objectClass = [ "olcdatabaseconfig" "olc${database}config" ];
+          olcDatabase = "{1}${database}";
+          olcDbDirectory = lib.mkDefault "/var/db/openldap";
+        };
+        "cn=schema".includes = lib.mkDefault (
+          map (schema: "${openldap}/etc/schema/${schema}.ldif") [ "core" "cosine" "inetorgperson" "nis" ]
+        );
+      }))
+    (mkDatabaseOption "rootpwFile" [ "olcRootPW" "path" ])
+    (mkDatabaseOption "suffix" [ "olcSuffix" ])
+    (mkDatabaseOption "dataDir" [ "olcDbDirectory" ])
+    (mkDatabaseOption "rootdn" [ "olcRootDN" ])
+    (mkDatabaseOption "rootpw" [ "olcRootPW" ])
+  ];
   options = {
-
     services.openldap = {
-
       enable = mkOption {
         type = types.bool;
         default = false;
@@ -77,224 +155,170 @@ in
         example = [ "ldaps:///" ];
       };
 
-      dataDir = mkOption {
-        type = types.path;
-        default = "/var/db/openldap";
-        description = "The database directory.";
-      };
-
-      defaultSchemas = mkOption {
-        type = types.bool;
-        default = true;
-        description = ''
-          Include the default schemas core, cosine, inetorgperson and nis.
-          This setting will be ignored if configDir is set.
-        '';
-      };
-
-      database = mkOption {
-        type = types.str;
-        default = "mdb";
-        description = ''
-          Database type to use for the LDAP.
-          This setting will be ignored if configDir is set.
-        '';
-      };
-
-      suffix = mkOption {
-        type = types.str;
-        example = "dc=example,dc=org";
-        description = ''
-          Specify the DN suffix of queries that will be passed to this backend
-          database.
-          This setting will be ignored if configDir is set.
-        '';
-      };
-
-      rootdn = mkOption {
-        type = types.str;
-        example = "cn=admin,dc=example,dc=org";
-        description = ''
-          Specify the distinguished name that is not subject to access control
-          or administrative limit restrictions for operations on this database.
-          This setting will be ignored if configDir is set.
-        '';
-      };
-
-      rootpw = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Password for the root user.
-          This setting will be ignored if configDir is set.
-          Using this option will store the root password in plain text in the
-          world-readable nix store. To avoid this the <literal>rootpwFile</literal> can be used.
+      settings = mkOption {
+        type = ldapAttrsType;
+        description = "Configuration for OpenLDAP, in OLC format";
+        example = lib.literalExample ''
+          {
+            attrs.olcLogLevel = [ "stats" ];
+            children = {
+              "cn=schema".includes = [
+                 "\${pkgs.openldap}/etc/schema/core.ldif"
+                 "\${pkgs.openldap}/etc/schema/cosine.ldif"
+                 "\${pkgs.openldap}/etc/schema/inetorgperson.ldif"
+              ];
+              "olcDatabase={-1}frontend" = {
+                attrs = {
+                  objectClass = "olcDatabaseConfig";
+                  olcDatabase = "{-1}frontend";
+                  olcAccess = [ "{0}to * by dn.exact=uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth manage stop by * none stop" ];
+                };
+              };
+              "olcDatabase={0}config" = {
+                attrs = {
+                  objectClass = "olcDatabaseConfig";
+                  olcDatabase = "{0}config";
+                  olcAccess = [ "{0}to * by * none break" ];
+                };
+              };
+              "olcDatabase={1}mdb" = {
+                attrs = {
+                  objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];
+                  olcDatabase = "{1}mdb";
+                  olcDbDirectory = "/var/db/ldap";
+                  olcDbIndex = [
+                    "objectClass eq"
+                    "cn pres,eq"
+                    "uid pres,eq"
+                    "sn pres,eq,subany"
+                  ];
+                  olcSuffix = "dc=example,dc=com";
+                  olcAccess = [ "{0}to * by * read break" ];
+                };
+              };
+            };
+          };
         '';
       };
 
-      rootpwFile = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          Password file for the root user.
-          The file should contain the string <literal>rootpw</literal> followed by the password.
-          e.g.: <literal>rootpw mysecurepassword</literal>
-        '';
-      };
-
-      logLevel = mkOption {
-        type = types.str;
-        default = "0";
-        example = "acl trace";
-        description = "The log level selector of slapd.";
-      };
-
+      # This option overrides settings
       configDir = mkOption {
         type = types.nullOr types.path;
         default = null;
-        description = "Use this optional config directory instead of using slapd.conf";
+        description = ''
+          Use this config directory instead of generating one from the
+          <literal>settings</literal> option. Overrides all NixOS settings. If
+          you use this option,ensure `olcPidFile` is set to `/run/slapd/slapd.conf`.
+        '';
         example = "/var/db/slapd.d";
       };
 
-      extraConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = "
-          slapd.conf configuration
-        ";
-        example = literalExample ''
-            '''
-            include ${openldap.out}/etc/schema/core.schema
-            include ${openldap.out}/etc/schema/cosine.schema
-            include ${openldap.out}/etc/schema/inetorgperson.schema
-            include ${openldap.out}/etc/schema/nis.schema
-
-            database bdb
-            suffix dc=example,dc=org
-            rootdn cn=admin,dc=example,dc=org
-            # NOTE: change after first start
-            rootpw secret
-            directory /var/db/openldap
-            '''
-          '';
-      };
-
       declarativeContents = mkOption {
-        type = with types; nullOr lines;
-        default = null;
+        type = with types; attrsOf lines;
+        default = {};
         description = ''
-          Declarative contents for the LDAP database, in LDIF format.
+          Declarative contents for the LDAP database, in LDIF format by suffix.
 
-          Note a few facts when using it. First, the database
-          <emphasis>must</emphasis> be stored in the directory defined by
-          <code>dataDir</code>. Second, all <code>dataDir</code> will be erased
-          when starting the LDAP server. Third, modifications to the database
-          are not prevented, they are just dropped on the next reboot of the
-          server. Finally, performance-wise the database and indexes are rebuilt
-          on each server startup, so this will slow down server startup,
+          All data will be erased when starting the LDAP server. Modifications
+          to the database are not prevented, they are just dropped on the next
+          reboot of the server. Performance-wise the database and indexes are
+          rebuilt on each server startup, so this will slow down server startup,
           especially with large databases.
         '';
-        example = ''
-          dn: dc=example,dc=org
-          objectClass: domain
-          dc: example
-
-          dn: ou=users,dc=example,dc=org
-          objectClass = organizationalUnit
-          ou: users
-
-          # ...
+        example = lib.literalExample ''
+          {
+            "dc=example,dc=org" = '''
+              dn= dn: dc=example,dc=org
+              objectClass: domain
+              dc: example
+
+              dn: ou=users,dc=example,dc=org
+              objectClass = organizationalUnit
+              ou: users
+
+              # ...
+            ''';
+          }
         '';
       };
-
-      extraDatabaseConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = ''
-          slapd.conf configuration after the database option.
-          This setting will be ignored if configDir is set.
-        '';
-        example = ''
-          # Indices to maintain for this directory
-          # unique id so equality match only
-          index uid eq
-          # allows general searching on commonname, givenname and email
-          index cn,gn,mail eq,sub
-          # allows multiple variants on surname searching
-          index sn eq,sub
-          # sub above includes subintial,subany,subfinal
-          # optimise department searches
-          index ou eq
-          # if searches will include objectClass uncomment following
-          # index objectClass eq
-          # shows use of default index parameter
-          index default eq,sub
-          # indices missing - uses default eq,sub
-          index telephonenumber
-
-          # other database parameters
-          # read more in slapd.conf reference section
-          cachesize 10000
-          checkpoint 128 15
-        '';
-      };
-
     };
-
-  };
-
-  meta = {
-    maintainers = [ lib.maintainers.mic92 ];
   };
 
-
-  ###### implementation
+  meta.maintainers = with lib.maintainters; [ mic92 kwohlfahrt ];
 
   config = mkIf cfg.enable {
-    assertions = [
-      {
-        assertion = cfg.configDir != null || cfg.rootpwFile != null || cfg.rootpw != null;
-        message = "services.openldap: Unless configDir is set, either rootpw or rootpwFile must be set";
-      }
-    ];
-
+    assertions = map (opt: {
+      assertion = ((getAttr opt cfg) != "_mkMergedOptionModule") -> (cfg.database != "_mkMergedOptionModule");
+      message = "Legacy OpenLDAP option `services.openldap.${opt}` requires `services.openldap.database` (use value \"mdb\" if unsure)";
+    }) legacyOptions;
     environment.systemPackages = [ openldap ];
 
+    # Literal attributes must always be set
+    services.openldap.settings = {
+      attrs = {
+        objectClass = "olcGlobal";
+        cn = "config";
+        olcPidFile = "/run/slapd/slapd.pid";
+      };
+      children."cn=schema".attrs = {
+        cn = "schema";
+        objectClass = "olcSchemaConfig";
+      };
+    };
+
     systemd.services.openldap = {
       description = "LDAP server";
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
-      preStart = ''
+      preStart = let
+        settingsFile = pkgs.writeText "config.ldif" (lib.concatStringsSep "\n" (attrsToLdif "cn=config" cfg.settings));
+
+        dbSettings = lib.filterAttrs (name: value: lib.hasPrefix "olcDatabase=" name) cfg.settings.children;
+        dataDirs = lib.mapAttrs' (name: value: lib.nameValuePair value.attrs.olcSuffix value.attrs.olcDbDirectory)
+          (lib.filterAttrs (_: value: value.attrs ? olcDbDirectory) dbSettings);
+        dataFiles = lib.mapAttrs (dn: contents: pkgs.writeText "${dn}.ldif" contents) cfg.declarativeContents;
+        mkLoadScript = dn: let
+          dataDir = lib.escapeShellArg (getAttr dn dataDirs);
+        in  ''
+          rm -rf ${dataDir}/*
+          ${openldap}/bin/slapadd -F ${lib.escapeShellArg configDir} -b ${dn} -l ${getAttr dn dataFiles}
+          chown -R "${cfg.user}:${cfg.group}" ${dataDir}
+        '';
+      in ''
         mkdir -p /run/slapd
         chown -R "${cfg.user}:${cfg.group}" /run/slapd
-        ${optionalString (cfg.declarativeContents != null) ''
-          rm -Rf "${cfg.dataDir}"
-        ''}
-        mkdir -p "${cfg.dataDir}"
-        ${optionalString (cfg.declarativeContents != null) ''
-          ${openldap.out}/bin/slapadd ${configOpts} -l ${dataFile}
-        ''}
-        chown -R "${cfg.user}:${cfg.group}" "${cfg.dataDir}"
 
-        ${openldap}/bin/slaptest ${configOpts}
+        mkdir -p ${lib.escapeShellArg configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)}
+        chown "${cfg.user}:${cfg.group}" ${lib.escapeShellArg configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)}
+
+        ${lib.optionalString (cfg.configDir == null) (''
+          rm -Rf ${configDir}/*
+          ${openldap}/bin/slapadd -F ${configDir} -bcn=config -l ${settingsFile}
+        '')}
+        chown -R "${cfg.user}:${cfg.group}" ${lib.escapeShellArg configDir}
+
+        ${lib.concatStrings (map mkLoadScript (lib.attrNames cfg.declarativeContents))}
+        ${openldap}/bin/slaptest -u -F ${lib.escapeShellArg configDir}
       '';
-      serviceConfig.ExecStart =
-        "${openldap.out}/libexec/slapd -d '${cfg.logLevel}' " +
-          "-u '${cfg.user}' -g '${cfg.group}' " +
-          "-h '${concatStringsSep " " cfg.urlList}' " +
-          "${configOpts}";
+      serviceConfig = {
+        ExecStart = lib.escapeShellArgs ([
+          "${openldap}/libexec/slapd" "-u" cfg.user "-g" cfg.group "-F" configDir
+          "-h" (lib.concatStringsSep " " cfg.urlList)
+        ]);
+        Type = "forking";
+        PIDFile = cfg.settings.attrs.olcPidFile;
+      };
     };
 
-    users.users.openldap =
-      { name = cfg.user;
+    users.users = lib.optionalAttrs (cfg.user == "openldap") {
+      openldap = {
         group = cfg.group;
-        uid = config.ids.uids.openldap;
-      };
-
-    users.groups.openldap =
-      { name = cfg.group;
-        gid = config.ids.gids.openldap;
+        isSystemUser = true;
       };
+    };
 
+    users.groups = lib.optionalAttrs (cfg.group == "openldap") {
+      openldap = {};
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/databases/postgresql.nix b/nixpkgs/nixos/modules/services/databases/postgresql.nix
index 5056d50153f6..f582b0592774 100644
--- a/nixpkgs/nixos/modules/services/databases/postgresql.nix
+++ b/nixpkgs/nixos/modules/services/databases/postgresql.nix
@@ -69,11 +69,16 @@ in
         type = types.lines;
         default = "";
         description = ''
-          Defines how users authenticate themselves to the server. By
-          default, "trust" access to local users will always be granted
-          along with any other custom options. If you do not want this,
-          set this option using "lib.mkForce" to override this
-          behaviour.
+          Defines how users authenticate themselves to the server. See the
+          <link xlink:href="https://www.postgresql.org/docs/current/auth-pg-hba-conf.html">
+          PostgreSQL documentation for pg_hba.conf</link>
+          for details on the expected format of this option. By default,
+          peer based authentication will be used for users connecting
+          via the Unix socket, and md5 password authentication will be
+          used for users connecting via TCP. Any added rules will be
+          inserted above the default rules. If you'd like to replace the
+          default rules entirely, you can use <function>lib.mkForce</function> in your
+          module.
         '';
       };
 
diff --git a/nixpkgs/nixos/modules/services/databases/redis.nix b/nixpkgs/nixos/modules/services/databases/redis.nix
index f1777854e141..6b8853ae390b 100644
--- a/nixpkgs/nixos/modules/services/databases/redis.nix
+++ b/nixpkgs/nixos/modules/services/databases/redis.nix
@@ -87,9 +87,12 @@ in
 
       bind = mkOption {
         type = with types; nullOr str;
-        default = null; # All interfaces
-        description = "The IP interface to bind to.";
-        example = "127.0.0.1";
+        default = "127.0.0.1";
+        description = ''
+          The IP interface to bind to.
+          <literal>null</literal> means "all interfaces".
+        '';
+        example = "192.0.2.1";
       };
 
       unixSocket = mkOption {
diff --git a/nixpkgs/nixos/modules/services/databases/riak-cs.nix b/nixpkgs/nixos/modules/services/databases/riak-cs.nix
deleted file mode 100644
index fa6ac8863318..000000000000
--- a/nixpkgs/nixos/modules/services/databases/riak-cs.nix
+++ /dev/null
@@ -1,202 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  cfg = config.services.riak-cs;
-
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    services.riak-cs = {
-
-      enable = mkEnableOption "riak-cs";
-
-      package = mkOption {
-        type = types.package;
-        default = pkgs.riak-cs;
-        defaultText = "pkgs.riak-cs";
-        example = literalExample "pkgs.riak-cs";
-        description = ''
-          Riak package to use.
-        '';
-      };
-
-      nodeName = mkOption {
-        type = types.str;
-        default = "riak-cs@127.0.0.1";
-        description = ''
-          Name of the Erlang node.
-        '';
-      };
-
-      anonymousUserCreation = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Anonymous user creation.
-        '';
-      };
-
-      riakHost = mkOption {
-        type = types.str;
-        default = "127.0.0.1:8087";
-        description = ''
-          Name of riak hosting service.
-        '';
-      };
-
-      listener = mkOption {
-        type = types.str;
-        default = "127.0.0.1:8080";
-        description = ''
-          Name of Riak CS listening service.
-        '';
-      };
-
-      stanchionHost = mkOption {
-        type = types.str;
-        default = "127.0.0.1:8085";
-        description = ''
-          Name of stanchion hosting service.
-        '';
-      };
-
-      stanchionSsl = mkOption {
-        type = types.bool;
-        default = true;
-        description = ''
-          Tell stanchion to use SSL.
-        '';
-      };
-
-      distributedCookie = mkOption {
-        type = types.str;
-        default = "riak";
-        description = ''
-          Cookie for distributed node communication.  All nodes in the
-          same cluster should use the same cookie or they will not be able to
-          communicate.
-        '';
-      };
-
-      dataDir = mkOption {
-        type = types.path;
-        default = "/var/db/riak-cs";
-        description = ''
-          Data directory for Riak CS.
-        '';
-      };
-
-      logDir = mkOption {
-        type = types.path;
-        default = "/var/log/riak-cs";
-        description = ''
-          Log directory for Riak CS.
-        '';
-      };
-
-      extraConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = ''
-          Additional text to be appended to <filename>riak-cs.conf</filename>.
-        '';
-      };
-
-      extraAdvancedConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = ''
-          Additional text to be appended to <filename>advanced.config</filename>.
-        '';
-      };
-    };
-
-  };
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-
-    environment.systemPackages = [ cfg.package ];
-    environment.etc."riak-cs/riak-cs.conf".text = ''
-      nodename = ${cfg.nodeName}
-      distributed_cookie = ${cfg.distributedCookie}
-
-      platform_log_dir = ${cfg.logDir}
-
-      riak_host = ${cfg.riakHost}
-      listener = ${cfg.listener}
-      stanchion_host = ${cfg.stanchionHost}
-
-      anonymous_user_creation = ${if cfg.anonymousUserCreation then "on" else "off"}
-
-      ${cfg.extraConfig}
-    '';
-
-    environment.etc."riak-cs/advanced.config".text = ''
-      ${cfg.extraAdvancedConfig}
-    '';
-
-    users.users.riak-cs = {
-      name = "riak-cs";
-      uid = config.ids.uids.riak-cs;
-      group = "riak";
-      description = "Riak CS server user";
-    };
-
-  systemd.services.riak-cs = {
-      description = "Riak CS Server";
-
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
-
-      path = [
-        pkgs.utillinux # for `logger`
-        pkgs.bash
-      ];
-
-      environment.HOME = "${cfg.dataDir}";
-      environment.RIAK_CS_DATA_DIR = "${cfg.dataDir}";
-      environment.RIAK_CS_LOG_DIR = "${cfg.logDir}";
-      environment.RIAK_CS_ETC_DIR = "/etc/riak";
-
-      preStart = ''
-        if ! test -e ${cfg.logDir}; then
-          mkdir -m 0755 -p ${cfg.logDir}
-          chown -R riak-cs ${cfg.logDir}
-        fi
-
-        if ! test -e ${cfg.dataDir}; then
-          mkdir -m 0700 -p ${cfg.dataDir}
-          chown -R riak-cs ${cfg.dataDir}
-        fi
-      '';
-
-      serviceConfig = {
-        ExecStart = "${cfg.package}/bin/riak-cs console";
-        ExecStop = "${cfg.package}/bin/riak-cs stop";
-        StandardInput = "tty";
-        User = "riak-cs";
-        Group = "riak-cs";
-        PermissionsStartOnly = true;
-        # Give Riak a decent amount of time to clean up.
-        TimeoutStopSec = 120;
-        LimitNOFILE = 65536;
-      };
-
-      unitConfig.RequiresMountsFor = [
-        "${cfg.dataDir}"
-        "${cfg.logDir}"
-        "/etc/riak"
-      ];
-    };
-  };
-}
diff --git a/nixpkgs/nixos/modules/services/databases/riak.nix b/nixpkgs/nixos/modules/services/databases/riak.nix
index 885215209bdf..657eeea87bf4 100644
--- a/nixpkgs/nixos/modules/services/databases/riak.nix
+++ b/nixpkgs/nixos/modules/services/databases/riak.nix
@@ -118,7 +118,7 @@ in
       after = [ "network.target" ];
 
       path = [
-        pkgs.utillinux # for `logger`
+        pkgs.util-linux # for `logger`
         pkgs.bash
       ];
 
diff --git a/nixpkgs/nixos/modules/services/databases/stanchion.nix b/nixpkgs/nixos/modules/services/databases/stanchion.nix
deleted file mode 100644
index 97e55bc70c47..000000000000
--- a/nixpkgs/nixos/modules/services/databases/stanchion.nix
+++ /dev/null
@@ -1,194 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  cfg = config.services.stanchion;
-
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    services.stanchion = {
-
-      enable = mkEnableOption "stanchion";
-
-      package = mkOption {
-        type = types.package;
-        default = pkgs.stanchion;
-        defaultText = "pkgs.stanchion";
-        example = literalExample "pkgs.stanchion";
-        description = ''
-          Stanchion package to use.
-        '';
-      };
-
-      nodeName = mkOption {
-        type = types.str;
-        default = "stanchion@127.0.0.1";
-        description = ''
-          Name of the Erlang node.
-        '';
-      };
-
-      adminKey = mkOption {
-        type = types.str;
-        default = "";
-        description = ''
-          Name of admin user.
-        '';
-      };
-
-      adminSecret = mkOption {
-        type = types.str;
-        default = "";
-        description = ''
-          Name of admin secret
-        '';
-      };
-
-      riakHost = mkOption {
-        type = types.str;
-        default = "127.0.0.1:8087";
-        description = ''
-          Name of riak hosting service.
-        '';
-      };
-
-      listener = mkOption {
-        type = types.str;
-        default = "127.0.0.1:8085";
-        description = ''
-          Name of Riak CS listening service.
-        '';
-      };
-
-      stanchionHost = mkOption {
-        type = types.str;
-        default = "127.0.0.1:8085";
-        description = ''
-          Name of stanchion hosting service.
-        '';
-      };
-
-      distributedCookie = mkOption {
-        type = types.str;
-        default = "riak";
-        description = ''
-          Cookie for distributed node communication.  All nodes in the
-          same cluster should use the same cookie or they will not be able to
-          communicate.
-        '';
-      };
-
-      dataDir = mkOption {
-        type = types.path;
-        default = "/var/db/stanchion";
-        description = ''
-          Data directory for Stanchion.
-        '';
-      };
-
-      logDir = mkOption {
-        type = types.path;
-        default = "/var/log/stanchion";
-        description = ''
-          Log directory for Stanchion.
-        '';
-      };
-
-      extraConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = ''
-          Additional text to be appended to <filename>stanchion.conf</filename>.
-        '';
-      };
-    };
-  };
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-
-    environment.systemPackages = [ cfg.package ];
-
-    environment.etc."stanchion/advanced.config".text = ''
-      [{stanchion, []}].
-    '';
-
-    environment.etc."stanchion/stanchion.conf".text = ''
-      listener = ${cfg.listener}
-
-      riak_host = ${cfg.riakHost}
-
-      ${optionalString (cfg.adminKey == "") "#"} admin.key=${optionalString (cfg.adminKey != "") cfg.adminKey}
-      ${optionalString (cfg.adminSecret == "") "#"} admin.secret=${optionalString (cfg.adminSecret != "") cfg.adminSecret}
-
-      platform_bin_dir = ${pkgs.stanchion}/bin
-      platform_data_dir = ${cfg.dataDir}
-      platform_etc_dir = /etc/stanchion
-      platform_lib_dir = ${pkgs.stanchion}/lib
-      platform_log_dir = ${cfg.logDir}
-
-      nodename = ${cfg.nodeName}
-
-      distributed_cookie = ${cfg.distributedCookie}
-
-      ${cfg.extraConfig}
-    '';
-
-    users.users.stanchion = {
-      name = "stanchion";
-      uid = config.ids.uids.stanchion;
-      group = "stanchion";
-      description = "Stanchion server user";
-    };
-
-    users.groups.stanchion.gid = config.ids.gids.stanchion;
-
-    systemd.tmpfiles.rules = [
-      "d '${cfg.logDir}' - stanchion stanchion --"
-      "d '${cfg.dataDir}' 0700 stanchion stanchion --"
-    ];
-
-    systemd.services.stanchion = {
-      description = "Stanchion Server";
-
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
-
-      path = [
-        pkgs.utillinux # for `logger`
-        pkgs.bash
-      ];
-
-      environment.HOME = "${cfg.dataDir}";
-      environment.STANCHION_DATA_DIR = "${cfg.dataDir}";
-      environment.STANCHION_LOG_DIR = "${cfg.logDir}";
-      environment.STANCHION_ETC_DIR = "/etc/stanchion";
-
-      serviceConfig = {
-        ExecStart = "${cfg.package}/bin/stanchion console";
-        ExecStop = "${cfg.package}/bin/stanchion stop";
-        StandardInput = "tty";
-        User = "stanchion";
-        Group = "stanchion";
-        # Give Stanchion a decent amount of time to clean up.
-        TimeoutStopSec = 120;
-        LimitNOFILE = 65536;
-      };
-
-      unitConfig.RequiresMountsFor = [
-        "${cfg.dataDir}"
-        "${cfg.logDir}"
-        "/etc/stanchion"
-      ];
-    };
-  };
-}
diff --git a/nixpkgs/nixos/modules/services/databases/victoriametrics.nix b/nixpkgs/nixos/modules/services/databases/victoriametrics.nix
index 0af5d2adf372..5b09115bb2fb 100644
--- a/nixpkgs/nixos/modules/services/databases/victoriametrics.nix
+++ b/nixpkgs/nixos/modules/services/databases/victoriametrics.nix
@@ -40,10 +40,10 @@ let cfg = config.services.victoriametrics; in
     systemd.services.victoriametrics = {
       description = "VictoriaMetrics time series database";
       after = [ "network.target" ];
+      startLimitBurst = 5;
       serviceConfig = {
         Restart = "on-failure";
         RestartSec = 1;
-        StartLimitBurst = 5;
         StateDirectory = "victoriametrics";
         DynamicUser = true;
         ExecStart = ''
diff --git a/nixpkgs/nixos/modules/services/desktops/flatpak.nix b/nixpkgs/nixos/modules/services/desktops/flatpak.nix
index 7da92cc9f264..d0f6b66328a4 100644
--- a/nixpkgs/nixos/modules/services/desktops/flatpak.nix
+++ b/nixpkgs/nixos/modules/services/desktops/flatpak.nix
@@ -15,6 +15,18 @@ in {
   options = {
     services.flatpak = {
       enable = mkEnableOption "flatpak";
+
+      guiPackages = mkOption {
+        internal = true;
+        type = types.listOf types.package;
+        default = [];
+        example = literalExample "[ pkgs.gnome3.gnome-software ]";
+        description = ''
+          Packages that provide an interface for flatpak
+          (like gnome-software) that will be automatically available
+          to all users when flatpak is enabled.
+        '';
+      };
     };
   };
 
@@ -28,7 +40,7 @@ in {
       }
     ];
 
-    environment.systemPackages = [ pkgs.flatpak ];
+    environment.systemPackages = [ pkgs.flatpak ] ++ cfg.guiPackages;
 
     services.dbus.packages = [ pkgs.flatpak ];
 
diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire.nix b/nixpkgs/nixos/modules/services/desktops/pipewire.nix
index 5aee59cfdcce..0ef988d9e69f 100644
--- a/nixpkgs/nixos/modules/services/desktops/pipewire.nix
+++ b/nixpkgs/nixos/modules/services/desktops/pipewire.nix
@@ -5,8 +5,18 @@ with lib;
 
 let
   cfg = config.services.pipewire;
-  packages = with pkgs; [ pipewire ];
+  enable32BitAlsaPlugins = cfg.alsa.support32Bit
+                           && pkgs.stdenv.isx86_64
+                           && pkgs.pkgsi686Linux.pipewire != null;
 
+  # The package doesn't output to $out/lib/pipewire directly so that the
+  # overlays can use the outputs to replace the originals in FHS environments.
+  #
+  # This doesn't work in general because of missing development information.
+  jack-libs = pkgs.runCommand "jack-libs" {} ''
+    mkdir -p "$out/lib"
+    ln -s "${cfg.package.jack}/lib" "$out/lib/pipewire"
+  '';
 in {
 
   meta = {
@@ -18,6 +28,16 @@ in {
     services.pipewire = {
       enable = mkEnableOption "pipewire service";
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.pipewire;
+        defaultText = "pkgs.pipewire";
+        example = literalExample "pkgs.pipewire";
+        description = ''
+          The pipewire derivation to use.
+        '';
+      };
+
       socketActivation = mkOption {
         default = true;
         type = types.bool;
@@ -25,17 +45,139 @@ in {
           Automatically run pipewire when connections are made to the pipewire socket.
         '';
       };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Literal string to append to /etc/pipewire/pipewire.conf.
+        '';
+      };
+
+      sessionManager = mkOption {
+        type = types.nullOr types.string;
+        default = null;
+        example = literalExample ''"''${pipewire}/bin/pipewire-media-session"'';
+        description = ''
+          Path to the pipewire session manager executable.
+        '';
+      };
+
+      sessionManagerArguments = mkOption {
+        type = types.listOf types.string;
+        default = [];
+        example = literalExample ''[ "-p" "bluez5.msbc-support=true" ]'';
+        description = ''
+          Arguments passed to the pipewire session manager.
+        '';
+      };
+
+      alsa = {
+        enable = mkEnableOption "ALSA support";
+        support32Bit = mkEnableOption "32-bit ALSA support on 64-bit systems";
+      };
+
+      jack = {
+        enable = mkEnableOption "JACK audio emulation";
+      };
+
+      pulse = {
+        enable = mkEnableOption "PulseAudio server emulation";
+      };
     };
   };
 
 
   ###### implementation
   config = mkIf cfg.enable {
-    environment.systemPackages = packages;
+    assertions = [
+      {
+        assertion = cfg.pulse.enable -> !config.hardware.pulseaudio.enable;
+        message = "PipeWire based PulseAudio server emulation replaces PulseAudio";
+      }
+      {
+        assertion = cfg.jack.enable -> !config.services.jack.jackd.enable;
+        message = "PipeWire based JACK emulation doesn't use the JACK service";
+      }
+    ];
+
+    services.pipewire.sessionManager = mkDefault "${cfg.package}/bin/pipewire-media-session";
+
+    environment.systemPackages = [ cfg.package ]
+                                 ++ lib.optional cfg.jack.enable jack-libs;
 
-    systemd.packages = packages;
+    systemd.packages = [ cfg.package ]
+                       ++ lib.optional cfg.pulse.enable cfg.package.pulse;
 
+    # PipeWire depends on DBUS but doesn't list it. Without this booting
+    # into a terminal results in the service crashing with an error.
     systemd.user.sockets.pipewire.wantedBy = lib.mkIf cfg.socketActivation [ "sockets.target" ];
-  };
+    systemd.user.sockets.pipewire-pulse.wantedBy = lib.mkIf (cfg.socketActivation && cfg.pulse.enable) ["sockets.target"];
+    systemd.user.services.pipewire.bindsTo = [ "dbus.service" ];
+    services.udev.packages = [ cfg.package ];
+
+    # If any paths are updated here they must also be updated in the package test.
+    environment.etc."alsa/conf.d/49-pipewire-modules.conf" = mkIf cfg.alsa.enable {
+      text = ''
+        pcm_type.pipewire {
+          libs.native = ${cfg.package.lib}/lib/alsa-lib/libasound_module_pcm_pipewire.so ;
+          ${optionalString enable32BitAlsaPlugins
+            "libs.32Bit = ${pkgs.pkgsi686Linux.pipewire.lib}/lib/alsa-lib/libasound_module_pcm_pipewire.so ;"}
+        }
+        ctl_type.pipewire {
+          libs.native = ${cfg.package.lib}/lib/alsa-lib/libasound_module_ctl_pipewire.so ;
+          ${optionalString enable32BitAlsaPlugins
+            "libs.32Bit = ${pkgs.pkgsi686Linux.pipewire.lib}/lib/alsa-lib/libasound_module_ctl_pipewire.so ;"}
+        }
+      '';
+    };
+    environment.etc."alsa/conf.d/50-pipewire.conf" = mkIf cfg.alsa.enable {
+      source = "${cfg.package}/share/alsa/alsa.conf.d/50-pipewire.conf";
+    };
+    environment.etc."alsa/conf.d/99-pipewire-default.conf" = mkIf cfg.alsa.enable {
+      source = "${cfg.package}/share/alsa/alsa.conf.d/99-pipewire-default.conf";
+    };
+    environment.sessionVariables.LD_LIBRARY_PATH =
+      lib.optional cfg.jack.enable "/run/current-system/sw/lib/pipewire";
+
+    environment.etc."pipewire/pipewire.conf" = {
+      # Adapted from src/daemon/pipewire.conf.in
+      text = ''
+        set-prop link.max-buffers 16 # version < 3 clients can't handle more
+
+        add-spa-lib audio.convert* audioconvert/libspa-audioconvert
+        add-spa-lib api.alsa.* alsa/libspa-alsa
+        add-spa-lib api.v4l2.* v4l2/libspa-v4l2
+        add-spa-lib api.libcamera.* libcamera/libspa-libcamera
+        add-spa-lib api.bluez5.* bluez5/libspa-bluez5
+        add-spa-lib api.vulkan.* vulkan/libspa-vulkan
+        add-spa-lib api.jack.* jack/libspa-jack
+        add-spa-lib support.* support/libspa-support
+
+        load-module libpipewire-module-rtkit # rt.prio=20 rt.time.soft=200000 rt.time.hard=200000
+        load-module libpipewire-module-protocol-native
+        load-module libpipewire-module-profiler
+        load-module libpipewire-module-metadata
+        load-module libpipewire-module-spa-device-factory
+        load-module libpipewire-module-spa-node-factory
+        load-module libpipewire-module-client-node
+        load-module libpipewire-module-client-device
+        load-module libpipewire-module-portal
+        load-module libpipewire-module-access
+        load-module libpipewire-module-adapter
+        load-module libpipewire-module-link-factory
+        load-module libpipewire-module-session-manager
+
+        create-object spa-node-factory factory.name=support.node.driver node.name=Dummy priority.driver=8000
 
+        exec ${cfg.sessionManager} ${lib.concatStringsSep " " cfg.sessionManagerArguments}
+
+        ${cfg.extraConfig}
+      '';
+    };
+
+    environment.etc."pipewire/media-session.d/with-alsa" = mkIf cfg.alsa.enable { text = ""; };
+    environment.etc."pipewire/media-session.d/with-pulseaudio" = mkIf cfg.pulse.enable { text = ""; };
+    environment.etc."pipewire/media-session.d/with-jack" = mkIf cfg.jack.enable { text = ""; };
+  };
 }
diff --git a/nixpkgs/nixos/modules/services/desktops/profile-sync-daemon.nix b/nixpkgs/nixos/modules/services/desktops/profile-sync-daemon.nix
index a8ac22ac1276..6206295272fc 100644
--- a/nixpkgs/nixos/modules/services/desktops/profile-sync-daemon.nix
+++ b/nixpkgs/nixos/modules/services/desktops/profile-sync-daemon.nix
@@ -36,7 +36,7 @@ in {
             description = "Profile Sync daemon";
             wants = [ "psd-resync.service" ];
             wantedBy = [ "default.target" ];
-            path = with pkgs; [ rsync kmod gawk nettools utillinux profile-sync-daemon ];
+            path = with pkgs; [ rsync kmod gawk nettools util-linux profile-sync-daemon ];
             unitConfig = {
               RequiresMountsFor = [ "/home/" ];
             };
@@ -55,7 +55,7 @@ in {
             wants = [ "psd-resync.timer" ];
             partOf = [ "psd.service" ];
             wantedBy = [ "default.target" ];
-            path = with pkgs; [ rsync kmod gawk nettools utillinux profile-sync-daemon ];
+            path = with pkgs; [ rsync kmod gawk nettools util-linux profile-sync-daemon ];
             serviceConfig = {
               Type = "oneshot";
               ExecStart = "${pkgs.profile-sync-daemon}/bin/profile-sync-daemon resync";
diff --git a/nixpkgs/nixos/modules/services/desktops/telepathy.nix b/nixpkgs/nixos/modules/services/desktops/telepathy.nix
index 34596bf78184..8c50d860e5bb 100644
--- a/nixpkgs/nixos/modules/services/desktops/telepathy.nix
+++ b/nixpkgs/nixos/modules/services/desktops/telepathy.nix
@@ -38,6 +38,11 @@ with lib;
 
     services.dbus.packages = [ pkgs.telepathy-mission-control ];
 
+    # Enable runtime optional telepathy in gnome-shell
+    services.xserver.desktopManager.gnome3.sessionPath = with pkgs; [
+      telepathy-glib
+      telepathy-logger
+    ];
   };
 
 }
diff --git a/nixpkgs/nixos/modules/services/development/blackfire.nix b/nixpkgs/nixos/modules/services/development/blackfire.nix
new file mode 100644
index 000000000000..6fd948cce38d
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/development/blackfire.nix
@@ -0,0 +1,65 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.blackfire-agent;
+
+  agentConfigFile = lib.generators.toINI {} {
+    blackfire =  cfg.settings;
+  };
+
+  agentSock = "blackfire/agent.sock";
+in {
+  meta = {
+    maintainers = pkgs.blackfire.meta.maintainers;
+    doc = ./blackfire.xml;
+  };
+
+  options = {
+    services.blackfire-agent = {
+      enable = lib.mkEnableOption "Blackfire profiler agent";
+      settings = lib.mkOption {
+        description = ''
+          See https://blackfire.io/docs/configuration/agent
+        '';
+        type = lib.types.submodule {
+          freeformType = with lib.types; attrsOf str;
+
+          options = {
+            server-id = lib.mkOption {
+              type = lib.types.str;
+              description = ''
+                Sets the server id used to authenticate with Blackfire
+
+                You can find your personal server-id at https://blackfire.io/my/settings/credentials
+              '';
+            };
+
+            server-token = lib.mkOption {
+              type = lib.types.str;
+              description = ''
+                Sets the server token used to authenticate with Blackfire
+
+                You can find your personal server-token at https://blackfire.io/my/settings/credentials
+              '';
+            };
+          };
+        };
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    environment.etc."blackfire/agent".text = agentConfigFile;
+
+    services.blackfire-agent.settings.socket = "unix:///run/${agentSock}";
+
+    systemd.services.blackfire-agent = {
+      description = "Blackfire agent";
+
+      serviceConfig = {
+        ExecStart = "${pkgs.blackfire}/bin/blackfire-agent";
+        RuntimeDirectory = "blackfire";
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/development/blackfire.xml b/nixpkgs/nixos/modules/services/development/blackfire.xml
new file mode 100644
index 000000000000..ad4af35788db
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/development/blackfire.xml
@@ -0,0 +1,45 @@
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="module-services-blackfire">
+ <title>Blackfire profiler</title>
+ <para>
+  <emphasis>Source:</emphasis>
+  <filename>modules/services/development/blackfire.nix</filename>
+ </para>
+ <para>
+  <emphasis>Upstream documentation:</emphasis>
+  <link xlink:href="https://blackfire.io/docs/introduction"/>
+ </para>
+ <para>
+  <link xlink:href="https://blackfire.io">Blackfire</link> is a proprietary tool for profiling applications. There are several languages supported by the product but currently only PHP support is packaged in Nixpkgs. The back-end consists of a module that is loaded into the language runtime (called <firstterm>probe</firstterm>) and a service (<firstterm>agent</firstterm>) that the probe connects to and that sends the profiles to the server.
+ </para>
+ <para>
+  To use it, you will need to enable the agent and the probe on your server. The exact method will depend on the way you use PHP but here is an example of NixOS configuration for PHP-FPM:
+<programlisting>let
+  php = pkgs.php.withExtensions ({ enabled, all }: enabled ++ (with all; [
+    blackfire
+  ]));
+in {
+  # Enable the probe extension for PHP-FPM.
+  services.phpfpm = {
+    phpPackage = php;
+  };
+
+  # Enable and configure the agent.
+  services.blackfire-agent = {
+    enable = true;
+    settings = {
+      # You will need to get credentials at https://blackfire.io/my/settings/credentials
+      # You can also use other options described in https://blackfire.io/docs/configuration/agent
+      server-id = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
+      server-token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
+    };
+  };
+
+  # Make the agent run on start-up.
+  # Alternately, you can start it manually with `systemctl start blackfire-agent`.
+  systemd.services.blackfire-agent.wantedBy = [ "phpfpm-foo.service" ];
+}</programlisting>
+ </para>
+ <para>
+  On your developer machine, you will also want to install <link xlink:href="https://blackfire.io/docs/up-and-running/installation#install-a-profiling-client">the client</link> (see <package>blackfire</package> package) or the browser extension to actually trigger the profiling.
+ </para>
+</chapter>
diff --git a/nixpkgs/nixos/modules/services/development/hoogle.nix b/nixpkgs/nixos/modules/services/development/hoogle.nix
index 1a98f005602a..cbf13f027de2 100644
--- a/nixpkgs/nixos/modules/services/development/hoogle.nix
+++ b/nixpkgs/nixos/modules/services/development/hoogle.nix
@@ -61,10 +61,8 @@ in {
         Restart = "always";
         ExecStart = ''${hoogleEnv}/bin/hoogle server --local --port ${toString cfg.port} --home ${cfg.home}'';
 
-        User = "nobody";
-        Group = "nogroup";
+        DynamicUser = true;
 
-        PrivateTmp = true;
         ProtectHome = true;
 
         RuntimeDirectory = "hoogle";
diff --git a/nixpkgs/nixos/modules/services/games/factorio.nix b/nixpkgs/nixos/modules/services/games/factorio.nix
index 4b2e1a3c07f0..73099ae33634 100644
--- a/nixpkgs/nixos/modules/services/games/factorio.nix
+++ b/nixpkgs/nixos/modules/services/games/factorio.nix
@@ -49,8 +49,13 @@ in
         default = 34197;
         description = ''
           The port to which the service should bind.
-
-          This option will also open up the UDP port in the firewall configuration.
+        '';
+      };
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to automatically open the specified UDP port in the firewall.
         '';
       };
       saveName = mkOption {
@@ -237,6 +242,6 @@ in
       };
     };
 
-    networking.firewall.allowedUDPPorts = [ cfg.port ];
+    networking.firewall.allowedUDPPorts = if cfg.openFirewall then [ cfg.port ] else [];
   };
 }
diff --git a/nixpkgs/nixos/modules/services/hardware/bluetooth.nix b/nixpkgs/nixos/modules/services/hardware/bluetooth.nix
index dfa39e7f6024..6f5a6d3bf288 100644
--- a/nixpkgs/nixos/modules/services/hardware/bluetooth.nix
+++ b/nixpkgs/nixos/modules/services/hardware/bluetooth.nix
@@ -15,6 +15,8 @@ in {
     hardware.bluetooth = {
       enable = mkEnableOption "support for Bluetooth";
 
+      hsphfpd.enable = mkEnableOption "support for hsphfpd[-prototype] implementation";
+
       powerOnBoot = mkOption {
         type    = types.bool;
         default = true;
@@ -72,7 +74,8 @@ in {
       };
     };
 
-    environment.systemPackages = [ bluez-bluetooth ];
+    environment.systemPackages = [ bluez-bluetooth ]
+      ++ optionals cfg.hsphfpd.enable [ pkgs.hsphfpd ];
 
     environment.etc."bluetooth/main.conf"= {
       source = pkgs.writeText "main.conf"
@@ -80,19 +83,42 @@ in {
     };
 
     services.udev.packages = [ bluez-bluetooth ];
-    services.dbus.packages = [ bluez-bluetooth ];
+    services.dbus.packages = [ bluez-bluetooth ]
+      ++ optionals cfg.hsphfpd.enable [ pkgs.hsphfpd ];
     systemd.packages       = [ bluez-bluetooth ];
 
     systemd.services = {
       bluetooth = {
         wantedBy = [ "bluetooth.target" ];
         aliases  = [ "dbus-org.bluez.service" ];
+        # restarting can leave people without a mouse/keyboard
+        unitConfig.X-RestartIfChanged = false;
       };
-    };
+    }
+      // (optionalAttrs cfg.hsphfpd.enable {
+        hsphfpd = {
+          after = [ "bluetooth.service" ];
+          requires = [ "bluetooth.service" ];
+          wantedBy = [ "multi-user.target" ];
+
+          description = "A prototype implementation used for connecting HSP/HFP Bluetooth devices";
+          serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/hsphfpd.pl";
+        };
+      })
+      ;
 
     systemd.user.services = {
       obex.aliases = [ "dbus-org.bluez.obex.service" ];
-    };
+    }
+      // (optionalAttrs cfg.hsphfpd.enable {
+        telephony_client = {
+          wantedBy = [ "default.target"];
+
+          description = "telephony_client for hsphfpd";
+          serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/telephony_client.pl";
+        };
+      })
+      ;
 
   };
 
diff --git a/nixpkgs/nixos/modules/services/hardware/fwupd.nix b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
index 222ac8e487eb..51eca19dca32 100644
--- a/nixpkgs/nixos/modules/services/hardware/fwupd.nix
+++ b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
@@ -11,8 +11,8 @@ let
     "fwupd/daemon.conf" = {
       source = pkgs.writeText "daemon.conf" ''
         [fwupd]
-        BlacklistDevices=${lib.concatStringsSep ";" cfg.blacklistDevices}
-        BlacklistPlugins=${lib.concatStringsSep ";" cfg.blacklistPlugins}
+        DisabledDevices=${lib.concatStringsSep ";" cfg.disabledDevices}
+        DisabledPlugins=${lib.concatStringsSep ";" cfg.disabledPlugins}
       '';
     };
     "fwupd/uefi.conf" = {
@@ -59,21 +59,21 @@ in {
         '';
       };
 
-      blacklistDevices = mkOption {
+      disabledDevices = mkOption {
         type = types.listOf types.str;
         default = [];
         example = [ "2082b5e0-7a64-478a-b1b2-e3404fab6dad" ];
         description = ''
-          Allow blacklisting specific devices by their GUID
+          Allow disabling specific devices by their GUID
         '';
       };
 
-      blacklistPlugins = mkOption {
+      disabledPlugins = mkOption {
         type = types.listOf types.str;
         default = [];
         example = [ "udev" ];
         description = ''
-          Allow blacklisting specific plugins
+          Allow disabling specific plugins
         '';
       };
 
@@ -105,11 +105,15 @@ in {
     };
   };
 
+  imports = [
+    (mkRenamedOptionModule [ "services" "fwupd" "blacklistDevices"] [ "services" "fwupd" "disabledDevices" ])
+    (mkRenamedOptionModule [ "services" "fwupd" "blacklistPlugins"] [ "services" "fwupd" "disabledPlugins" ])
+  ];
 
   ###### implementation
   config = mkIf cfg.enable {
     # Disable test related plug-ins implicitly so that users do not have to care about them.
-    services.fwupd.blacklistPlugins = cfg.package.defaultBlacklistedPlugins;
+    services.fwupd.disabledPlugins = cfg.package.defaultDisabledPlugins;
 
     environment.systemPackages = [ cfg.package ];
 
diff --git a/nixpkgs/nixos/modules/services/hardware/lcd.nix b/nixpkgs/nixos/modules/services/hardware/lcd.nix
index d78d742cd318..dc8595ea60cd 100644
--- a/nixpkgs/nixos/modules/services/hardware/lcd.nix
+++ b/nixpkgs/nixos/modules/services/hardware/lcd.nix
@@ -151,14 +151,13 @@ in with lib; {
         description = "LCDproc - client";
         after = [ "lcdd.service" ];
         wantedBy = [ "lcd.target" ];
+        # Allow restarting for eternity
+        startLimitIntervalSec = lib.mkIf cfg.client.restartForever 0;
         serviceConfig = serviceCfg // {
           ExecStart = "${pkg}/bin/lcdproc -f -c ${clientCfg}";
           # If the server is being restarted at the same time, the client will
           # fail as it cannot connect, so space it out a bit.
           RestartSec = "5";
-          # Allow restarting for eternity
-          StartLimitIntervalSec = lib.mkIf cfg.client.restartForever "0";
-          StartLimitBurst = lib.mkIf cfg.client.restartForever "0";
         };
       };
     };
diff --git a/nixpkgs/nixos/modules/services/hardware/sane.nix b/nixpkgs/nixos/modules/services/hardware/sane.nix
index b344dfc20610..03070a8f9e7c 100644
--- a/nixpkgs/nixos/modules/services/hardware/sane.nix
+++ b/nixpkgs/nixos/modules/services/hardware/sane.nix
@@ -148,7 +148,7 @@ in
           # saned needs to distinguish between IPv4 and IPv6 to open matching data sockets.
           BindIPv6Only = "ipv6-only";
           Accept = true;
-          MaxConnections = 1;
+          MaxConnections = 64;
         };
       };
 
diff --git a/nixpkgs/nixos/modules/services/hardware/thermald.nix b/nixpkgs/nixos/modules/services/hardware/thermald.nix
index b7be0e89d0c6..aa936ac09d1d 100644
--- a/nixpkgs/nixos/modules/services/hardware/thermald.nix
+++ b/nixpkgs/nixos/modules/services/hardware/thermald.nix
@@ -24,32 +24,30 @@ in {
         description = "the thermald manual configuration file.";
       };
 
-      adaptive = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Whether to enable adaptive mode, only working on kernel versions greater than 5.8.
-          Thermald will detect this itself, safe to enable on kernel versions below 5.8.
-        '';
+      package = mkOption {
+        type = types.package;
+        default = pkgs.thermald;
+        defaultText = "pkgs.thermald";
+        description = "Which thermald package to use.";
       };
     };
   };
 
   ###### implementation
   config = mkIf cfg.enable {
-    services.dbus.packages = [ pkgs.thermald ];
+    services.dbus.packages = [ cfg.package ];
 
     systemd.services.thermald = {
       description = "Thermal Daemon Service";
       wantedBy = [ "multi-user.target" ];
       serviceConfig = {
         ExecStart = ''
-          ${pkgs.thermald}/sbin/thermald \
+          ${cfg.package}/sbin/thermald \
             --no-daemon \
             ${optionalString cfg.debug "--loglevel=debug"} \
             ${optionalString (cfg.configFile != null) "--config-file ${cfg.configFile}"} \
-            ${optionalString cfg.adaptive "--adaptive"} \
-            --dbus-enable
+            --dbus-enable \
+            --adaptive
         '';
       };
     };
diff --git a/nixpkgs/nixos/modules/services/hardware/throttled.nix b/nixpkgs/nixos/modules/services/hardware/throttled.nix
index 7617c4492d7c..1905eb565c6d 100644
--- a/nixpkgs/nixos/modules/services/hardware/throttled.nix
+++ b/nixpkgs/nixos/modules/services/hardware/throttled.nix
@@ -26,5 +26,11 @@ in {
       if cfg.extraConfig != ""
       then pkgs.writeText "lenovo_fix.conf" cfg.extraConfig
       else "${pkgs.throttled}/etc/lenovo_fix.conf";
+
+    # Kernel 5.9 spams warnings whenever userspace writes to CPU MSRs.
+    # See https://github.com/erpalma/throttled/issues/215
+    boot.kernelParams =
+      optional (versionAtLeast config.boot.kernelPackages.kernel.version "5.9")
+      "msr.allow_writes=on";
   };
 }
diff --git a/nixpkgs/nixos/modules/services/hardware/tlp.nix b/nixpkgs/nixos/modules/services/hardware/tlp.nix
index 4230f2edd279..eb53f565a67f 100644
--- a/nixpkgs/nixos/modules/services/hardware/tlp.nix
+++ b/nixpkgs/nixos/modules/services/hardware/tlp.nix
@@ -39,7 +39,7 @@ in
         default = "";
         description = ''
           Verbatim additional configuration variables for TLP.
-          DEPRECATED: use services.tlp.config instead.
+          DEPRECATED: use services.tlp.settings instead.
         '';
       };
     };
diff --git a/nixpkgs/nixos/modules/services/hardware/trezord.nix b/nixpkgs/nixos/modules/services/hardware/trezord.nix
index 2594ac743710..8c609bbf825b 100644
--- a/nixpkgs/nixos/modules/services/hardware/trezord.nix
+++ b/nixpkgs/nixos/modules/services/hardware/trezord.nix
@@ -47,7 +47,7 @@ in {
     services.udev.packages = [ pkgs.trezor-udev-rules ];
 
     systemd.services.trezord = {
-      description = "TREZOR Bridge";
+      description = "Trezor Bridge";
       after = [ "systemd-udev-settle.service" "network.target" ];
       wantedBy = [ "multi-user.target" ];
       path = [];
diff --git a/nixpkgs/nixos/modules/services/hardware/udev.nix b/nixpkgs/nixos/modules/services/hardware/udev.nix
index 587b9b0234aa..63027f7744dc 100644
--- a/nixpkgs/nixos/modules/services/hardware/udev.nix
+++ b/nixpkgs/nixos/modules/services/hardware/udev.nix
@@ -57,8 +57,8 @@ let
         substituteInPlace $i \
           --replace \"/sbin/modprobe \"${pkgs.kmod}/bin/modprobe \
           --replace \"/sbin/mdadm \"${pkgs.mdadm}/sbin/mdadm \
-          --replace \"/sbin/blkid \"${pkgs.utillinux}/sbin/blkid \
-          --replace \"/bin/mount \"${pkgs.utillinux}/bin/mount \
+          --replace \"/sbin/blkid \"${pkgs.util-linux}/sbin/blkid \
+          --replace \"/bin/mount \"${pkgs.util-linux}/bin/mount \
           --replace /usr/bin/readlink ${pkgs.coreutils}/bin/readlink \
           --replace /usr/bin/basename ${pkgs.coreutils}/bin/basename
       done
@@ -205,7 +205,7 @@ in
       extraRules = mkOption {
         default = "";
         example = ''
-          KERNEL=="eth*", ATTR{address}=="00:1D:60:B9:6D:4F", NAME="my_fast_network_card"
+          SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:1D:60:B9:6D:4F", KERNEL=="eth*", NAME="my_fast_network_card"
         '';
         type = types.lines;
         description = ''
@@ -280,7 +280,7 @@ in
 
     services.udev.packages = [ extraUdevRules extraHwdbFile ];
 
-    services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux udev ];
+    services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.util-linux udev ];
 
     boot.kernelParams = mkIf (!config.networking.usePredictableInterfaceNames) [ "net.ifnames=0" ];
 
diff --git a/nixpkgs/nixos/modules/services/hardware/undervolt.nix b/nixpkgs/nixos/modules/services/hardware/undervolt.nix
index 054ffa35050a..9c2f78a755dd 100644
--- a/nixpkgs/nixos/modules/services/hardware/undervolt.nix
+++ b/nixpkgs/nixos/modules/services/hardware/undervolt.nix
@@ -3,7 +3,12 @@
 with lib;
 let
   cfg = config.services.undervolt;
-  cliArgs = lib.cli.toGNUCommandLineShell {} {
+
+  mkPLimit = limit: window:
+    if (isNull limit && isNull window) then null
+    else assert asserts.assertMsg (!isNull limit && !isNull window) "Both power limit and window must be set";
+      "${toString limit} ${toString window}";
+  cliArgs = lib.cli.toGNUCommandLine {} {
     inherit (cfg)
       verbose
       temp
@@ -21,6 +26,9 @@ let
 
     temp-bat = cfg.tempBat;
     temp-ac = cfg.tempAc;
+
+    power-limit-long = mkPLimit cfg.p1.limit cfg.p1.window;
+    power-limit-short = mkPLimit cfg.p2.limit cfg.p2.window;
   };
 in
 {
@@ -104,6 +112,40 @@ in
       '';
     };
 
+    p1.limit = mkOption {
+      type = with types; nullOr int;
+      default = null;
+      description = ''
+        The P1 Power Limit in Watts.
+        Both limit and window must be set.
+      '';
+    };
+    p1.window = mkOption {
+      type = with types; nullOr (oneOf [ float int ]);
+      default = null;
+      description = ''
+        The P1 Time Window in seconds.
+        Both limit and window must be set.
+      '';
+    };
+
+    p2.limit = mkOption {
+      type = with types; nullOr int;
+      default = null;
+      description = ''
+        The P2 Power Limit in Watts.
+        Both limit and window must be set.
+      '';
+    };
+    p2.window = mkOption {
+      type = with types; nullOr (oneOf [ float int ]);
+      default = null;
+      description = ''
+        The P2 Time Window in seconds.
+        Both limit and window must be set.
+      '';
+    };
+
     useTimer = mkOption {
       type = types.bool;
       default = false;
@@ -133,7 +175,7 @@ in
       serviceConfig = {
         Type = "oneshot";
         Restart = "no";
-        ExecStart = "${pkgs.undervolt}/bin/undervolt ${cliArgs}";
+        ExecStart = "${pkgs.undervolt}/bin/undervolt ${toString cliArgs}";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/logging/promtail.nix b/nixpkgs/nixos/modules/services/logging/promtail.nix
new file mode 100644
index 000000000000..19b12daa4152
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/logging/promtail.nix
@@ -0,0 +1,86 @@
+{ config, lib, pkgs, ... }: with lib;
+let
+  cfg = config.services.promtail;
+
+  prettyJSON = conf: pkgs.runCommandLocal "promtail-config.json" {} ''
+    echo '${builtins.toJSON conf}' | ${pkgs.buildPackages.jq}/bin/jq 'del(._module)' > $out
+  '';
+
+  allowSystemdJournal = cfg.configuration ? scrape_configs && lib.any (v: v ? journal) cfg.configuration.scrape_configs;
+in {
+  options.services.promtail = with types; {
+    enable = mkEnableOption "the Promtail ingresser";
+
+
+    configuration = mkOption {
+      type = (pkgs.formats.json {}).type;
+      description = ''
+        Specify the configuration for Promtail in Nix.
+      '';
+    };
+
+    extraFlags = mkOption {
+      type = listOf str;
+      default = [];
+      example = [ "--server.http-listen-port=3101" ];
+      description = ''
+        Specify a list of additional command line flags,
+        which get escaped and are then passed to Loki.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.promtail.configuration.positions.filename = mkDefault "/var/cache/promtail/positions.yaml";
+
+    systemd.services.promtail = {
+      description = "Promtail log ingress";
+      wantedBy = [ "multi-user.target" ];
+      stopIfChanged = false;
+
+      serviceConfig = {
+        Restart = "on-failure";
+
+        ExecStart = "${pkgs.grafana-loki}/bin/promtail -config.file=${prettyJSON cfg.configuration} ${escapeShellArgs cfg.extraFlags}";
+
+        ProtectSystem = "strict";
+        ProtectHome = true;
+        PrivateTmp = true;
+        PrivateDevices = true;
+        ProtectKernelTunables = true;
+        ProtectControlGroups = true;
+        RestrictSUIDSGID = true;
+        PrivateMounts = true;
+        CacheDirectory = "promtail";
+
+        User = "promtail";
+        Group = "promtail";
+
+        CapabilityBoundingSet = "";
+        NoNewPrivileges = true;
+
+        ProtectKernelModules = true;
+        SystemCallArchitectures = "native";
+        ProtectKernelLogs = true;
+        ProtectClock = true;
+
+        LockPersonality = true;
+        ProtectHostname = true;
+        RestrictRealtime = true;
+        MemoryDenyWriteExecute = true;
+        PrivateUsers = true;
+
+        SupplementaryGroups = lib.optional (allowSystemdJournal) "systemd-journal";
+      } // (optionalAttrs (!pkgs.stdenv.isAarch64) { # FIXME: figure out why this breaks on aarch64
+        SystemCallFilter = "@system-service";
+      });
+    };
+
+    users.groups.promtail = {};
+    users.users.promtail = {
+      description = "Promtail service user";
+      isSystemUser = true;
+      group = "promtail";
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/logging/vector.nix b/nixpkgs/nixos/modules/services/logging/vector.nix
new file mode 100644
index 000000000000..a7c54ad75fde
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/logging/vector.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let cfg = config.services.vector;
+
+in {
+  options.services.vector = {
+    enable = mkEnableOption "Vector";
+
+    journaldAccess = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable Vector to access journald.
+      '';
+    };
+
+    settings = mkOption {
+      type = (pkgs.formats.json { }).type;
+      default = { };
+      description = ''
+        Specify the configuration for Vector in Nix.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    users.groups.vector = { };
+    users.users.vector = {
+      description = "Vector service user";
+      group = "vector";
+      isSystemUser = true;
+    };
+    systemd.services.vector = {
+      description = "Vector event and log aggregator";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-online.target" ];
+      requires = [ "network-online.target" ];
+      serviceConfig = let
+        format = pkgs.formats.toml { };
+        conf = format.generate "vector.toml" cfg.settings;
+        validateConfig = file:
+          pkgs.runCommand "validate-vector-conf" { } ''
+            ${pkgs.vector}/bin/vector validate --no-topology --no-environment "${file}"
+            ln -s "${file}" "$out"
+          '';
+      in {
+        ExecStart = "${pkgs.vector}/bin/vector --config ${validateConfig conf}";
+        User = "vector";
+        Group = "vector";
+        Restart = "no";
+        StateDirectory = "vector";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+        # This group is required for accessing journald.
+        SupplementaryGroups = mkIf cfg.journaldAccess "systemd-journal";
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/mail/dovecot.nix b/nixpkgs/nixos/modules/services/mail/dovecot.nix
index c166ef68f292..03e7e40e388e 100644
--- a/nixpkgs/nixos/modules/services/mail/dovecot.nix
+++ b/nixpkgs/nixos/modules/services/mail/dovecot.nix
@@ -84,11 +84,9 @@ let
 
     (
       optionalString (cfg.mailboxes != {}) ''
-        protocol imap {
-          namespace inbox {
-            inbox=yes
-            ${concatStringsSep "\n" (map mailboxConfig (attrValues cfg.mailboxes))}
-          }
+        namespace inbox {
+          inbox=yes
+          ${concatStringsSep "\n" (map mailboxConfig (attrValues cfg.mailboxes))}
         }
       ''
     )
@@ -429,12 +427,12 @@ in
       wantedBy = [ "multi-user.target" ];
       restartTriggers = [ cfg.configFile modulesDir ];
 
+      startLimitIntervalSec = 60;  # 1 min
       serviceConfig = {
         ExecStart = "${dovecotPkg}/sbin/dovecot -F";
         ExecReload = "${dovecotPkg}/sbin/doveadm reload";
         Restart = "on-failure";
         RestartSec = "1s";
-        StartLimitInterval = "1min";
         RuntimeDirectory = [ "dovecot2" ];
       };
 
diff --git a/nixpkgs/nixos/modules/services/mail/freepops.nix b/nixpkgs/nixos/modules/services/mail/freepops.nix
deleted file mode 100644
index 5b729ca50a5e..000000000000
--- a/nixpkgs/nixos/modules/services/mail/freepops.nix
+++ /dev/null
@@ -1,89 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.services.mail.freepopsd;
-in
-
-{
-  options = {
-    services.mail.freepopsd = {
-      enable = mkOption {
-        default = false;
-        type = with types; bool;
-        description = ''
-          Enables Freepops, a POP3 webmail wrapper.
-        '';
-      };
-
-      port = mkOption {
-        default = 2000;
-        type = with types; uniq int;
-        description = ''
-          Port on which the pop server will listen.
-        '';
-      };
-
-      threads = mkOption {
-        default = 5;
-        type = with types; uniq int;
-        description = ''
-          Max simultaneous connections.
-        '';
-      };
-
-      bind = mkOption {
-        default = "0.0.0.0";
-        type = types.str;
-        description = ''
-          Bind over an IPv4 address instead of any.
-        '';
-      };
-
-      logFile = mkOption {
-        default = "/var/log/freepopsd";
-        example = "syslog";
-        type = types.str;
-        description = ''
-          Filename of the log file or syslog to rely on the logging daemon.
-        '';
-      };
-
-      suid = {
-        user = mkOption {
-          default = "nobody";
-          type = types.str;
-          description = ''
-            User name under which freepopsd will be after binding the port.
-          '';
-        };
-
-        group = mkOption {
-          default = "nogroup";
-          type = types.str;
-          description = ''
-            Group under which freepopsd will be after binding the port.
-          '';
-        };
-      };
-
-    };
-  };
-
-  config = mkIf cfg.enable {
-    systemd.services.freepopsd = {
-      description = "Freepopsd (webmail over POP3)";
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-      script = ''
-        ${pkgs.freepops}/bin/freepopsd \
-          -p ${toString cfg.port} \
-          -t ${toString cfg.threads} \
-          -b ${cfg.bind} \
-          -vv -l ${cfg.logFile} \
-          -s ${cfg.suid.user}.${cfg.suid.group}
-      '';
-    };
-  };
-}
diff --git a/nixpkgs/nixos/modules/services/mail/mailman.nix b/nixpkgs/nixos/modules/services/mail/mailman.nix
index 115730e29d5e..c0fed360af86 100644
--- a/nixpkgs/nixos/modules/services/mail/mailman.nix
+++ b/nixpkgs/nixos/modules/services/mail/mailman.nix
@@ -33,7 +33,7 @@ let
   webSettingsJSON = pkgs.writeText "settings.json" (builtins.toJSON webSettings);
 
   # TODO: Should this be RFC42-ised so that users can set additional options without modifying the module?
-  mtaConfig = pkgs.writeText "mailman-postfix.cfg" ''
+  postfixMtaConfig = pkgs.writeText "mailman-postfix.cfg" ''
     [postfix]
     postmap_command: ${pkgs.postfix}/bin/postmap
     transport_file_type: hash
@@ -76,7 +76,7 @@ in {
       enable = mkOption {
         type = types.bool;
         default = false;
-        description = "Enable Mailman on this host. Requires an active Postfix installation.";
+        description = "Enable Mailman on this host. Requires an active MTA on the host (e.g. Postfix).";
       };
 
       package = mkOption {
@@ -87,6 +87,20 @@ in {
         description = "Mailman package to use";
       };
 
+      enablePostfix = mkOption {
+        type = types.bool;
+        default = true;
+        example = false;
+        description = ''
+          Enable Postfix integration. Requires an active Postfix installation.
+
+          If you want to use another MTA, set this option to false and configure
+          settings in services.mailman.settings.mta.
+
+          Refer to the Mailman manual for more info.
+        '';
+      };
+
       siteOwner = mkOption {
         type = types.str;
         example = "postmaster@example.org";
@@ -177,7 +191,7 @@ in {
         pid_file = "/run/mailman/master.pid";
       };
 
-      mta.configuration = lib.mkDefault "${mtaConfig}";
+      mta.configuration = lib.mkDefault (if cfg.enablePostfix then "${postfixMtaConfig}" else throw "When Mailman Postfix integration is disabled, set `services.mailman.settings.mta.configuration` to the path of the config file required to integrate with your MTA.");
 
       "archiver.hyperkitty" = lib.mkIf cfg.hyperkitty.enable {
         class = "mailman_hyperkitty.Archiver";
@@ -206,14 +220,22 @@ in {
               See <https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html>.
             '';
           };
-    in [
+    in (lib.optionals cfg.enablePostfix [
       { assertion = postfix.enable;
-        message = "Mailman requires Postfix";
+        message = ''
+          Mailman's default NixOS configuration requires Postfix to be enabled.
+
+          If you want to use another MTA, set services.mailman.enablePostfix
+          to false and configure settings in services.mailman.settings.mta.
+
+          Refer to <https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html>
+          for more info.
+        '';
       }
       (requirePostfixHash [ "relayDomains" ] "postfix_domains")
       (requirePostfixHash [ "config" "transport_maps" ] "postfix_lmtp")
       (requirePostfixHash [ "config" "local_recipient_maps" ] "postfix_lmtp")
-    ];
+    ]);
 
     users.users.mailman = {
       description = "GNU Mailman";
@@ -260,7 +282,7 @@ in {
 
     environment.systemPackages = [ cfg.package ] ++ (with pkgs; [ mailman-web ]);
 
-    services.postfix = {
+    services.postfix = lib.mkIf cfg.enablePostfix {
       recipientDelimiter = "+";         # bake recipient addresses in mail envelopes via VERP
       config = {
         owner_request_special = "no";   # Mailman handles -owner addresses on its own
diff --git a/nixpkgs/nixos/modules/services/mail/mailman.xml b/nixpkgs/nixos/modules/services/mail/mailman.xml
index cbe50ed0b917..8da491ccbe9f 100644
--- a/nixpkgs/nixos/modules/services/mail/mailman.xml
+++ b/nixpkgs/nixos/modules/services/mail/mailman.xml
@@ -13,9 +13,9 @@
   </para>
 
   <section xml:id="module-services-mailman-basic-usage">
-    <title>Basic usage</title>
+    <title>Basic usage with Postfix</title>
     <para>
-      For a basic configuration, the following settings are suggested:
+      For a basic configuration with Postfix as the MTA, the following settings are suggested:
       <programlisting>{ config, ... }: {
   services.postfix = {
     enable = true;
@@ -56,4 +56,39 @@
       necessary, but outside the scope of the Mailman module.
     </para>
   </section>
+  <section xml:id="module-services-mailman-other-mtas">
+    <title>Using with other MTAs</title>
+    <para>
+      Mailman also supports other MTA, though with a little bit more configuration. For example, to use Mailman with Exim, you can use the following settings:
+      <programlisting>{ config, ... }: {
+  services = {
+    mailman = {
+      enable = true;
+      siteOwner = "mailman@example.org";
+      <link linkend="opt-services.mailman.enablePostfix">enablePostfix</link> = false;
+      settings.mta = {
+        incoming = "mailman.mta.exim4.LMTP";
+        outgoing = "mailman.mta.deliver.deliver";
+        lmtp_host = "localhost";
+        lmtp_port = "8024";
+        smtp_host = "localhost";
+        smtp_port = "25";
+        configuration = "python:mailman.config.exim4";
+      };
+    };
+    exim = {
+      enable = true;
+      # You can configure Exim in a separate file to reduce configuration.nix clutter
+      config = builtins.readFile ./exim.conf;
+    };
+  };
+}</programlisting>
+    </para>
+    <para>
+      The exim config needs some special additions to work with Mailman. Currently
+      NixOS can't manage Exim config with such granularity. Please refer to
+      <link xlink:href="https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html">Mailman documentation</link>
+      for more info on configuring Mailman for working with Exim.
+    </para>
+  </section>
 </chapter>
diff --git a/nixpkgs/nixos/modules/services/mail/postfix.nix b/nixpkgs/nixos/modules/services/mail/postfix.nix
index d777af2901e9..37ba98339a6c 100644
--- a/nixpkgs/nixos/modules/services/mail/postfix.nix
+++ b/nixpkgs/nixos/modules/services/mail/postfix.nix
@@ -52,7 +52,7 @@ let
       };
 
       type = mkOption {
-        type = types.enum [ "inet" "unix" "fifo" "pass" ];
+        type = types.enum [ "inet" "unix" "unix-dgram" "fifo" "pass" ];
         default = "unix";
         example = "inet";
         description = "The type of the service";
@@ -834,12 +834,6 @@ in
       };
 
       services.postfix.masterConfig = {
-        smtp_inet = {
-          name = "smtp";
-          type = "inet";
-          private = false;
-          command = "smtpd";
-        };
         pickup = {
           private = false;
           wakeup = 60;
@@ -921,6 +915,12 @@ in
           in concatLists (mapAttrsToList mkKeyVal cfg.submissionOptions);
         };
       } // optionalAttrs cfg.enableSmtp {
+        smtp_inet = {
+          name = "smtp";
+          type = "inet";
+          private = false;
+          command = "smtpd";
+        };
         smtp = {};
         relay = {
           command = "smtp";
diff --git a/nixpkgs/nixos/modules/services/mail/roundcube.nix b/nixpkgs/nixos/modules/services/mail/roundcube.nix
index a0bbab64985b..ee7aa7e22fb9 100644
--- a/nixpkgs/nixos/modules/services/mail/roundcube.nix
+++ b/nixpkgs/nixos/modules/services/mail/roundcube.nix
@@ -204,6 +204,11 @@ in
     };
     systemd.services.phpfpm-roundcube.after = [ "roundcube-setup.service" ];
 
+    # Restart on config changes.
+    systemd.services.phpfpm-roundcube.restartTriggers = [
+      config.environment.etc."roundcube/config.inc.php".source
+    ];
+
     systemd.services.roundcube-setup = mkMerge [
       (mkIf (cfg.database.host == "localhost") {
         requires = [ "postgresql.service" ];
diff --git a/nixpkgs/nixos/modules/services/mail/rspamd.nix b/nixpkgs/nixos/modules/services/mail/rspamd.nix
index aacdbe2aeed2..2f9d28195bd8 100644
--- a/nixpkgs/nixos/modules/services/mail/rspamd.nix
+++ b/nixpkgs/nixos/modules/services/mail/rspamd.nix
@@ -153,7 +153,7 @@ let
 
       ${concatStringsSep "\n" (mapAttrsToList (name: value: let
           includeName = if name == "rspamd_proxy" then "proxy" else name;
-          tryOverride = if value.extraConfig == "" then "true" else "false";
+          tryOverride = boolToString (value.extraConfig == "");
         in ''
         worker "${value.type}" {
           type = "${value.type}";
@@ -371,6 +371,9 @@ in
     };
     services.postfix.config = mkIf cfg.postfix.enable cfg.postfix.config;
 
+    systemd.services.postfix.serviceConfig.SupplementaryGroups =
+      mkIf cfg.postfix.enable [ postfixCfg.group ];
+
     # Allow users to run 'rspamc' and 'rspamadm'.
     environment.systemPackages = [ pkgs.rspamd ];
 
@@ -394,21 +397,50 @@ in
       restartTriggers = [ rspamdDir ];
 
       serviceConfig = {
-        ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -c /etc/rspamd/rspamd.conf -f";
+        ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} -c /etc/rspamd/rspamd.conf -f";
         Restart = "always";
+
+        User = "${cfg.user}";
+        Group = "${cfg.group}";
+        SupplementaryGroups = mkIf cfg.postfix.enable [ postfixCfg.group ];
+
         RuntimeDirectory = "rspamd";
+        RuntimeDirectoryMode = "0755";
+        StateDirectory = "rspamd";
+        StateDirectoryMode = "0700";
+
+        AmbientCapabilities = [];
+        CapabilityBoundingSet = [];
+        DevicePolicy = "closed";
+        LockPersonality = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateMounts = true;
         PrivateTmp = true;
+        # we need to chown socket to rspamd-milter
+        PrivateUsers = !cfg.postfix.enable;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectSystem = "strict";
+        RemoveIPC = true;
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+        SystemCallFilter = "@system-service";
+        UMask = "0077";
       };
-
-      preStart = ''
-        ${pkgs.coreutils}/bin/mkdir -p /var/lib/rspamd
-        ${pkgs.coreutils}/bin/chown ${cfg.user}:${cfg.group} /var/lib/rspamd
-      '';
     };
   };
   imports = [
     (mkRemovedOptionModule [ "services" "rspamd" "socketActivation" ]
-	     "Socket activation never worked correctly and could at this time not be fixed and so was removed")
+       "Socket activation never worked correctly and could at this time not be fixed and so was removed")
     (mkRenamedOptionModule [ "services" "rspamd" "bindSocket" ] [ "services" "rspamd" "workers" "normal" "bindSockets" ])
     (mkRenamedOptionModule [ "services" "rspamd" "bindUISocket" ] [ "services" "rspamd" "workers" "controller" "bindSockets" ])
     (mkRemovedOptionModule [ "services" "rmilter" ] "Use services.rspamd.* instead to set up milter service")
diff --git a/nixpkgs/nixos/modules/services/mail/sympa.nix b/nixpkgs/nixos/modules/services/mail/sympa.nix
index 0cad09927b2f..491b6dba9aa4 100644
--- a/nixpkgs/nixos/modules/services/mail/sympa.nix
+++ b/nixpkgs/nixos/modules/services/mail/sympa.nix
@@ -513,10 +513,6 @@ in
           include ${config.services.nginx.package}/conf/fastcgi_params;
 
           fastcgi_pass unix:/run/sympa/wwsympa.socket;
-          fastcgi_split_path_info ^(${loc})(.*)$;
-
-          fastcgi_param PATH_INFO       $fastcgi_path_info;
-          fastcgi_param SCRIPT_FILENAME ${pkg}/lib/sympa/cgi/wwsympa.fcgi;
         '';
       }) // {
         "/static-sympa/".alias = "${dataDir}/static_content/";
diff --git a/nixpkgs/nixos/modules/services/misc/autorandr.nix b/nixpkgs/nixos/modules/services/misc/autorandr.nix
index cf7fb5f78d3d..dfb418af6ede 100644
--- a/nixpkgs/nixos/modules/services/misc/autorandr.nix
+++ b/nixpkgs/nixos/modules/services/misc/autorandr.nix
@@ -37,9 +37,9 @@ in {
       description = "Autorandr execution hook";
       after = [ "sleep.target" ];
 
+      startLimitIntervalSec = 5;
+      startLimitBurst = 1;
       serviceConfig = {
-        StartLimitInterval = 5;
-        StartLimitBurst = 1;
         ExecStart = "${pkgs.autorandr}/bin/autorandr --batch --change --default ${cfg.defaultTarget}";
         Type = "oneshot";
         RemainAfterExit = false;
diff --git a/nixpkgs/nixos/modules/services/misc/cfdyndns.nix b/nixpkgs/nixos/modules/services/misc/cfdyndns.nix
index dcf416022734..15af1f50da1d 100644
--- a/nixpkgs/nixos/modules/services/misc/cfdyndns.nix
+++ b/nixpkgs/nixos/modules/services/misc/cfdyndns.nix
@@ -6,6 +6,12 @@ let
   cfg = config.services.cfdyndns;
 in
 {
+  imports = [
+    (mkRemovedOptionModule
+      [ "services" "cfdyndns" "apikey" ]
+      "Use services.cfdyndns.apikeyFile instead.")
+  ];
+
   options = {
     services.cfdyndns = {
       enable = mkEnableOption "Cloudflare Dynamic DNS Client";
@@ -17,10 +23,12 @@ in
         '';
       };
 
-      apikey = mkOption {
-        type = types.str;
+      apikeyFile = mkOption {
+        default = null;
+        type = types.nullOr types.str;
         description = ''
-          The API Key to use to authenticate to CloudFlare.
+          The path to a file containing the API Key
+          used to authenticate with CloudFlare.
         '';
       };
 
@@ -45,13 +53,17 @@ in
         Type = "simple";
         User = config.ids.uids.cfdyndns;
         Group = config.ids.gids.cfdyndns;
-        ExecStart = "/bin/sh -c '${pkgs.cfdyndns}/bin/cfdyndns'";
       };
       environment = {
         CLOUDFLARE_EMAIL="${cfg.email}";
-        CLOUDFLARE_APIKEY="${cfg.apikey}";
         CLOUDFLARE_RECORDS="${concatStringsSep "," cfg.records}";
       };
+      script = ''
+        ${optionalString (cfg.apikeyFile != null) ''
+          export CLOUDFLARE_APIKEY="$(cat ${escapeShellArg cfg.apikeyFile})"
+        ''}
+        ${pkgs.cfdyndns}/bin/cfdyndns
+      '';
     };
 
     users.users = {
diff --git a/nixpkgs/nixos/modules/services/misc/cgminer.nix b/nixpkgs/nixos/modules/services/misc/cgminer.nix
index 7635c2a0f4e9..fa9c8c54509e 100644
--- a/nixpkgs/nixos/modules/services/misc/cgminer.nix
+++ b/nixpkgs/nixos/modules/services/misc/cgminer.nix
@@ -126,12 +126,12 @@ in
         GPU_USE_SYNC_OBJECTS = "1";
       };
 
+      startLimitIntervalSec = 60;  # 1 min
       serviceConfig = {
         ExecStart = "${pkgs.cgminer}/bin/cgminer --syslog --text-only --config ${cgminerConfig}";
         User = cfg.user;
         RestartSec = "30s";
         Restart = "always";
-        StartLimitInterval = "1m";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/misc/disnix.nix b/nixpkgs/nixos/modules/services/misc/disnix.nix
index 69386cdbb381..41483d80a2dd 100644
--- a/nixpkgs/nixos/modules/services/misc/disnix.nix
+++ b/nixpkgs/nixos/modules/services/misc/disnix.nix
@@ -34,6 +34,14 @@ in
         defaultText = "pkgs.disnix";
       };
 
+      enableProfilePath = mkEnableOption "exposing the Disnix profiles in the system's PATH";
+
+      profiles = mkOption {
+        type = types.listOf types.string;
+        default = [ "default" ];
+        example = [ "default" ];
+        description = "Names of the Disnix profiles to expose in the system's PATH";
+      };
     };
 
   };
@@ -44,6 +52,7 @@ in
     dysnomia.enable = true;
 
     environment.systemPackages = [ pkgs.disnix ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService;
+    environment.variables.PATH = lib.optionals cfg.enableProfilePath (map (profileName: "/nix/var/nix/profiles/disnix/${profileName}/bin" ) cfg.profiles);
 
     services.dbus.enable = true;
     services.dbus.packages = [ pkgs.disnix ];
@@ -68,7 +77,8 @@ in
           ++ optional config.services.postgresql.enable "postgresql.service"
           ++ optional config.services.tomcat.enable "tomcat.service"
           ++ optional config.services.svnserve.enable "svnserve.service"
-          ++ optional config.services.mongodb.enable "mongodb.service";
+          ++ optional config.services.mongodb.enable "mongodb.service"
+          ++ optional config.services.influxdb.enable "influxdb.service";
 
         restartIfChanged = false;
 
diff --git a/nixpkgs/nixos/modules/services/misc/domoticz.nix b/nixpkgs/nixos/modules/services/misc/domoticz.nix
new file mode 100644
index 000000000000..b1353d484048
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/misc/domoticz.nix
@@ -0,0 +1,51 @@
+{ lib, pkgs, config, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.domoticz;
+  pkgDesc = "Domoticz home automation";
+
+in {
+
+  options = {
+
+    services.domoticz = {
+      enable = mkEnableOption pkgDesc;
+
+      bind = mkOption {
+        type = types.str;
+        default = "0.0.0.0";
+        description = "IP address to bind to.";
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 8080;
+        description = "Port to bind to for HTTP, set to 0 to disable HTTP.";
+      };
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.services."domoticz" = {
+      description = pkgDesc;
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-online.target" ];
+      serviceConfig = {
+        DynamicUser = true;
+        StateDirectory = "domoticz";
+        Restart = "always";
+        ExecStart = ''
+          ${pkgs.domoticz}/bin/domoticz -noupdates -www ${toString cfg.port} -wwwbind ${cfg.bind} -sslwww 0 -userdata /var/lib/domoticz -approot ${pkgs.domoticz}/share/domoticz/ -pidfile /var/run/domoticz.pid
+        '';
+      };
+    };
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/misc/dysnomia.nix b/nixpkgs/nixos/modules/services/misc/dysnomia.nix
index 4b52963500d1..eb94791fbbff 100644
--- a/nixpkgs/nixos/modules/services/misc/dysnomia.nix
+++ b/nixpkgs/nixos/modules/services/misc/dysnomia.nix
@@ -66,6 +66,19 @@ let
       ) (builtins.attrNames cfg.components)}
     '';
   };
+
+  dysnomiaFlags = {
+    enableApacheWebApplication = config.services.httpd.enable;
+    enableAxis2WebService = config.services.tomcat.axis2.enable;
+    enableDockerContainer = config.virtualisation.docker.enable;
+    enableEjabberdDump = config.services.ejabberd.enable;
+    enableMySQLDatabase = config.services.mysql.enable;
+    enablePostgreSQLDatabase = config.services.postgresql.enable;
+    enableTomcatWebApplication = config.services.tomcat.enable;
+    enableMongoDatabase = config.services.mongodb.enable;
+    enableSubversionRepository = config.services.svnserve.enable;
+    enableInfluxDatabase = config.services.influxdb.enable;
+  };
 in
 {
   options = {
@@ -117,6 +130,12 @@ in
         description = "A list of paths containing additional modules that are added to the search folders";
         default = [];
       };
+
+      enableLegacyModules = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Whether to enable Dysnomia legacy process and wrapper modules";
+      };
     };
   };
 
@@ -142,34 +161,48 @@ in
 
     environment.systemPackages = [ cfg.package ];
 
-    dysnomia.package = 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;
-      enableInfluxDatabase = config.services.influxdb.enable;
+    dysnomia.package = pkgs.dysnomia.override (origArgs: dysnomiaFlags // lib.optionalAttrs (cfg.enableLegacyModules) {
+      enableLegacy = builtins.trace ''
+        WARNING: Dysnomia has been configured to use the legacy 'process' and 'wrapper'
+        modules for compatibility reasons! If you rely on these modules, consider
+        migrating to better alternatives.
+
+        More information: https://raw.githubusercontent.com/svanderburg/dysnomia/f65a9a84827bcc4024d6b16527098b33b02e4054/README-legacy.md
+
+        If you have migrated already or don't rely on these Dysnomia modules, you can
+        disable legacy mode with the following NixOS configuration option:
+
+        dysnomia.enableLegacyModules = false;
+
+        In a future version of Dysnomia (and NixOS) the legacy option will go away!
+      '' true;
     });
 
     dysnomia.properties = {
       hostname = config.networking.hostName;
       inherit (config.nixpkgs.localSystem) system;
 
-      supportedTypes = (import "${pkgs.stdenv.mkDerivation {
-        name = "supportedtypes";
-        buildCommand = ''
-          ( echo -n "[ "
-            cd ${cfg.package}/libexec/dysnomia
-            for i in *
-            do
-                echo -n "\"$i\" "
-            done
-            echo -n " ]") > $out
-        '';
-      }}");
+      supportedTypes = [
+        "echo"
+        "fileset"
+        "process"
+        "wrapper"
+
+        # These are not base modules, but they are still enabled because they work with technology that are always enabled in NixOS
+        "systemd-unit"
+        "sysvinit-script"
+        "nixos-configuration"
+      ]
+      ++ optional (dysnomiaFlags.enableApacheWebApplication) "apache-webapplication"
+      ++ optional (dysnomiaFlags.enableAxis2WebService) "axis2-webservice"
+      ++ optional (dysnomiaFlags.enableDockerContainer) "docker-container"
+      ++ optional (dysnomiaFlags.enableEjabberdDump) "ejabberd-dump"
+      ++ optional (dysnomiaFlags.enableInfluxDatabase) "influx-database"
+      ++ optional (dysnomiaFlags.enableMySQLDatabase) "mysql-database"
+      ++ optional (dysnomiaFlags.enablePostgreSQLDatabase) "postgresql-database"
+      ++ optional (dysnomiaFlags.enableTomcatWebApplication) "tomcat-webapplication"
+      ++ optional (dysnomiaFlags.enableMongoDatabase) "mongo-database"
+      ++ optional (dysnomiaFlags.enableSubversionRepository) "subversion-repository";
     };
 
     dysnomia.containers = lib.recursiveUpdate ({
@@ -185,9 +218,9 @@ in
     }; }
     // lib.optionalAttrs (config.services.mysql.enable) { mysql-database = {
         mysqlPort = config.services.mysql.port;
+        mysqlSocket = "/run/mysqld/mysqld.sock";
       } // lib.optionalAttrs cfg.enableAuthentication {
         mysqlUsername = "root";
-        mysqlPassword = builtins.readFile (config.services.mysql.rootPassword);
       };
     }
     // lib.optionalAttrs (config.services.postgresql.enable) { postgresql-database = {
@@ -199,6 +232,13 @@ in
       tomcatPort = 8080;
     }; }
     // lib.optionalAttrs (config.services.mongodb.enable) { mongo-database = {}; }
+    // lib.optionalAttrs (config.services.influxdb.enable) {
+      influx-database = {
+        influxdbUsername = config.services.influxdb.user;
+        influxdbDataDir = "${config.services.influxdb.dataDir}/data";
+        influxdbMetaDir = "${config.services.influxdb.dataDir}/meta";
+      };
+    }
     // lib.optionalAttrs (config.services.svnserve.enable) { subversion-repository = {
       svnBaseDir = config.services.svnserve.svnBaseDir;
     }; }) cfg.extraContainerProperties;
diff --git a/nixpkgs/nixos/modules/services/misc/fstrim.nix b/nixpkgs/nixos/modules/services/misc/fstrim.nix
index b8841a7fe74c..5258f5acb410 100644
--- a/nixpkgs/nixos/modules/services/misc/fstrim.nix
+++ b/nixpkgs/nixos/modules/services/misc/fstrim.nix
@@ -31,7 +31,7 @@ in {
 
   config = mkIf cfg.enable {
 
-    systemd.packages = [ pkgs.utillinux ];
+    systemd.packages = [ pkgs.util-linux ];
 
     systemd.timers.fstrim = {
       timerConfig = {
diff --git a/nixpkgs/nixos/modules/services/misc/gitlab.nix b/nixpkgs/nixos/modules/services/misc/gitlab.nix
index 9896b8023e44..35a9dccdff28 100644
--- a/nixpkgs/nixos/modules/services/misc/gitlab.nix
+++ b/nixpkgs/nixos/modules/services/misc/gitlab.nix
@@ -43,9 +43,16 @@ let
 
     [gitlab-shell]
     dir = "${cfg.packages.gitlab-shell}"
+
+    [hooks]
+    custom_hooks_dir = "${cfg.statePath}/custom_hooks"
+
+    [gitlab]
     secret_file = "${cfg.statePath}/gitlab_shell_secret"
-    gitlab_url = "http+unix://${pathUrlQuote gitlabSocket}"
-    http_settings = { self_signed_cert = false }
+    url = "http+unix://${pathUrlQuote gitlabSocket}"
+
+    [gitlab.http-settings]
+    self_signed_cert = false
 
     ${concatStringsSep "\n" (attrValues (mapAttrs (k: v: ''
     [[storage]]
@@ -61,7 +68,6 @@ let
     repos_path = "${cfg.statePath}/repositories";
     secret_file = "${cfg.statePath}/gitlab_shell_secret";
     log_file = "${cfg.statePath}/log/gitlab-shell.log";
-    custom_hooks_dir = "${cfg.statePath}/custom_hooks";
     redis = {
       bin = "${pkgs.redis}/bin/redis-cli";
       host = "127.0.0.1";
@@ -73,6 +79,11 @@ let
 
   redisConfig.production.url = cfg.redisUrl;
 
+  pagesArgs = [
+    "-pages-domain" gitlabConfig.production.pages.host
+    "-pages-root" "${gitlabConfig.production.shared.path}/pages"
+  ] ++ cfg.pagesExtraArgs;
+
   gitlabConfig = {
     # These are the default settings from config/gitlab.example.yml
     production = flip recursiveUpdate cfg.extraConfig {
@@ -114,6 +125,7 @@ let
         receive_pack = true;
       };
       workhorse.secret_file = "${cfg.statePath}/.gitlab_workhorse_secret";
+      gitlab_kas.secret_file = "${cfg.statePath}/.gitlab_kas_secret";
       git.bin_path = "git";
       monitoring = {
         ip_whitelist = [ "127.0.0.0/8" "::1/128" ];
@@ -236,6 +248,13 @@ in {
         description = "Reference to the gitaly package";
       };
 
+      packages.pages = mkOption {
+        type = types.package;
+        default = pkgs.gitlab-pages;
+        defaultText = "pkgs.gitlab-pages";
+        description = "Reference to the gitlab-pages package";
+      };
+
       statePath = mkOption {
         type = types.str;
         default = "/var/gitlab/state";
@@ -451,6 +470,12 @@ in {
         };
       };
 
+      pagesExtraArgs = mkOption {
+        type = types.listOf types.str;
+        default = [ "-listen-proxy" "127.0.0.1:8090" ];
+        description = "Arguments to pass to the gitlab-pages daemon";
+      };
+
       secrets.secretFile = mkOption {
         type = with types; nullOr path;
         default = null;
@@ -635,7 +660,7 @@ in {
       script = ''
         set -eu
 
-        PSQL="${pkgs.utillinux}/bin/runuser -u ${pgsql.superUser} -- psql --port=${toString pgsql.port}"
+        PSQL="${pkgs.util-linux}/bin/runuser -u ${pgsql.superUser} -- psql --port=${toString pgsql.port}"
 
         $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${cfg.databaseName}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${cfg.databaseName}" OWNER "${cfg.databaseUsername}"'
         current_owner=$($PSQL -tAc "SELECT pg_catalog.pg_get_userbyid(datdba) FROM pg_catalog.pg_database WHERE datname = '${cfg.databaseName}'")
@@ -650,6 +675,7 @@ in {
             rm "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}"
         fi
         $PSQL '${cfg.databaseName}' -tAc "CREATE EXTENSION IF NOT EXISTS pg_trgm"
+        $PSQL '${cfg.databaseName}' -tAc "CREATE EXTENSION IF NOT EXISTS btree_gist;"
       '';
 
       serviceConfig = {
@@ -732,7 +758,8 @@ in {
     };
 
     systemd.services.gitaly = {
-      after = [ "network.target" ];
+      after = [ "network.target" "gitlab.service" ];
+      bindsTo = [ "gitlab.service" ];
       wantedBy = [ "multi-user.target" ];
       path = with pkgs; [
         openssh
@@ -754,6 +781,26 @@ in {
       };
     };
 
+    systemd.services.gitlab-pages = mkIf (gitlabConfig.production.pages.enabled or false) {
+      description = "GitLab static pages daemon";
+      after = [ "network.target" "redis.service" "gitlab.service" ]; # gitlab.service creates configs
+      wantedBy = [ "multi-user.target" ];
+
+      path = [ pkgs.unzip ];
+
+      serviceConfig = {
+        Type = "simple";
+        TimeoutSec = "infinity";
+        Restart = "on-failure";
+
+        User = cfg.user;
+        Group = cfg.group;
+
+        ExecStart = "${cfg.packages.pages}/bin/gitlab-pages ${escapeShellArgs pagesArgs}";
+        WorkingDirectory = gitlabEnv.HOME;
+      };
+    };
+
     systemd.services.gitlab-workhorse = {
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
@@ -801,7 +848,7 @@ in {
     };
 
     systemd.services.gitlab = {
-      after = [ "gitlab-workhorse.service" "gitaly.service" "network.target" "gitlab-postgresql.service" "redis.service" ];
+      after = [ "gitlab-workhorse.service" "network.target" "gitlab-postgresql.service" "redis.service" ];
       requires = [ "gitlab-sidekiq.service" ];
       wantedBy = [ "multi-user.target" ];
       environment = gitlabEnv;
diff --git a/nixpkgs/nixos/modules/services/misc/gogs.nix b/nixpkgs/nixos/modules/services/misc/gogs.nix
index c5070aaa356a..d7233f10c7cb 100644
--- a/nixpkgs/nixos/modules/services/misc/gogs.nix
+++ b/nixpkgs/nixos/modules/services/misc/gogs.nix
@@ -25,7 +25,6 @@ let
     HTTP_ADDR = ${cfg.httpAddress}
     HTTP_PORT = ${toString cfg.httpPort}
     ROOT_URL = ${cfg.rootUrl}
-    STATIC_ROOT_PATH = ${cfg.staticRootPath}
 
     [session]
     COOKIE_NAME = session
@@ -179,13 +178,6 @@ in
         '';
       };
 
-      staticRootPath = mkOption {
-        type = types.str;
-        default = "${pkgs.gogs.data}";
-        example = "/var/lib/gogs/data";
-        description = "Upper level of template and static files path.";
-      };
-
       extraConfig = mkOption {
         type = types.str;
         default = "";
diff --git a/nixpkgs/nixos/modules/services/misc/home-assistant.nix b/nixpkgs/nixos/modules/services/misc/home-assistant.nix
index 0477254e7c18..1f2e13f37325 100644
--- a/nixpkgs/nixos/modules/services/misc/home-assistant.nix
+++ b/nixpkgs/nixos/modules/services/misc/home-assistant.nix
@@ -245,7 +245,11 @@ in {
         Group = "hass";
         Restart = "on-failure";
         ProtectSystem = "strict";
-        ReadWritePaths = "${cfg.configDir}";
+        ReadWritePaths = let
+          cfgPath = [ "config" "homeassistant" "allowlist_external_dirs" ];
+          value = attrByPath cfgPath [] cfg;
+          allowPaths = if isList value then value else singleton value;
+        in [ "${cfg.configDir}" ] ++ allowPaths;
         KillSignal = "SIGINT";
         PrivateTmp = true;
         RemoveIPC = true;
diff --git a/nixpkgs/nixos/modules/services/misc/jellyfin.nix b/nixpkgs/nixos/modules/services/misc/jellyfin.nix
index 0493dadea94e..6a47dc3628f4 100644
--- a/nixpkgs/nixos/modules/services/misc/jellyfin.nix
+++ b/nixpkgs/nixos/modules/services/misc/jellyfin.nix
@@ -45,6 +45,46 @@ in
         CacheDirectory = "jellyfin";
         ExecStart = "${cfg.package}/bin/jellyfin --datadir '/var/lib/${StateDirectory}' --cachedir '/var/cache/${CacheDirectory}'";
         Restart = "on-failure";
+
+        # Security options:
+
+        NoNewPrivileges = true;
+
+        AmbientCapabilities = "";
+        CapabilityBoundingSet = "";
+
+        # ProtectClock= adds DeviceAllow=char-rtc r
+        DeviceAllow = "";
+
+        LockPersonality = true;
+
+        PrivateTmp = true;
+        PrivateDevices = true;
+        PrivateUsers = true;
+
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+
+        RemoveIPC = true;
+
+        RestrictNamespaces = true;
+        # AF_NETLINK needed because Jellyfin monitors the network connection
+        RestrictAddressFamilies = [ "AF_NETLINK" "AF_INET" "AF_INET6" ];
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+
+        SystemCallArchitectures = "native";
+        SystemCallErrorNumber = "EPERM";
+        SystemCallFilter = [
+          "@system-service"
+
+          "~@chown" "~@cpu-emulation" "~@debug" "~@keyring" "~@memlock" "~@module"
+          "~@obsolete" "~@privileged" "~@setuid"
+        ];
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/misc/klipper.nix b/nixpkgs/nixos/modules/services/misc/klipper.nix
new file mode 100644
index 000000000000..2f04c011a650
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/misc/klipper.nix
@@ -0,0 +1,59 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.services.klipper;
+  package = pkgs.klipper;
+  format = pkgs.formats.ini { mkKeyValue = generators.mkKeyValueDefault {} ":"; };
+in
+{
+  ##### interface
+  options = {
+    services.klipper = {
+      enable = mkEnableOption "Klipper, the 3D printer firmware";
+
+      octoprintIntegration = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Allows Octoprint to control Klipper.";
+      };
+
+      settings = mkOption {
+        type = format.type;
+        default = { };
+        description = ''
+          Configuration for Klipper. See the <link xlink:href="https://www.klipper3d.org/Overview.html#configuration-and-tuning-guides">documentation</link>
+          for supported values.
+        '';
+      };
+    };
+  };
+
+  ##### implementation
+  config = mkIf cfg.enable {
+    assertions = [{
+      assertion = cfg.octoprintIntegration -> config.services.octoprint.enable;
+      message = "Option klipper.octoprintIntegration requires Octoprint to be enabled on this system. Please enable services.octoprint to use it.";
+    }];
+
+    environment.etc."klipper.cfg".source = format.generate "klipper.cfg" cfg.settings;
+
+    systemd.services.klipper = {
+      description = "Klipper 3D Printer Firmware";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      serviceConfig = {
+        ExecStart = "${package}/lib/klipper/klippy.py --input-tty=/run/klipper/tty /etc/klipper.cfg";
+        RuntimeDirectory = "klipper";
+        SupplementaryGroups = [ "dialout" ];
+        WorkingDirectory = "${package}/lib";
+      } // (if cfg.octoprintIntegration then {
+        Group = config.services.octoprint.group;
+        User = config.services.octoprint.user;
+      } else {
+        DynamicUser = true;
+        User = "klipper";
+      });
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/misc/matrix-appservice-discord.nix b/nixpkgs/nixos/modules/services/misc/matrix-appservice-discord.nix
index 49c41ff637a8..71d1227f4ff7 100644
--- a/nixpkgs/nixos/modules/services/misc/matrix-appservice-discord.nix
+++ b/nixpkgs/nixos/modules/services/misc/matrix-appservice-discord.nix
@@ -5,7 +5,7 @@ with lib;
 let
   dataDir = "/var/lib/matrix-appservice-discord";
   registrationFile = "${dataDir}/discord-registration.yaml";
-  appDir = "${pkgs.matrix-appservice-discord}/lib/node_modules/matrix-appservice-discord";
+  appDir = "${pkgs.matrix-appservice-discord}/${pkgs.matrix-appservice-discord.passthru.nodeAppDir}";
   cfg = config.services.matrix-appservice-discord;
   # TODO: switch to configGen.json once RFC42 is implemented
   settingsFile = pkgs.writeText "matrix-appservice-discord-settings.json" (builtins.toJSON cfg.settings);
@@ -22,12 +22,6 @@ in {
         default = {
           database = {
             filename = "${dataDir}/discord.db";
-
-            # TODO: remove those old config keys once the following issues are solved:
-            # * https://github.com/Half-Shot/matrix-appservice-discord/issues/490
-            # * https://github.com/Half-Shot/matrix-appservice-discord/issues/498
-            userStorePath = "${dataDir}/user-store.db";
-            roomStorePath = "${dataDir}/room-store.db";
           };
 
           # empty values necessary for registration file generation
diff --git a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix b/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix
index 3eb1073387fe..3abb9b7d69c8 100644
--- a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix
+++ b/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix
@@ -131,7 +131,12 @@ in {
       plugins = mkOption {
         type = types.listOf types.package;
         default = [ ];
-        defaultText = "with config.services.matrix-synapse.package.plugins [ matrix-synapse-ldap3 matrix-synapse-pam ]";
+        example = literalExample ''
+          with config.services.matrix-synapse.package.plugins; [
+            matrix-synapse-ldap3
+            matrix-synapse-pam
+          ];
+        '';
         description = ''
           List of additional Matrix plugins to make available.
         '';
@@ -708,7 +713,7 @@ in {
             ${ concatMapStringsSep "\n  " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) }
             --keys-directory ${cfg.dataDir}
         '';
-        ExecReload = "${pkgs.utillinux}/bin/kill -HUP $MAINPID";
+        ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID";
         Restart = "on-failure";
       };
     };
diff --git a/nixpkgs/nixos/modules/services/misc/mautrix-telegram.nix b/nixpkgs/nixos/modules/services/misc/mautrix-telegram.nix
index c5e8a5b85ec2..caeb4b04164f 100644
--- a/nixpkgs/nixos/modules/services/misc/mautrix-telegram.nix
+++ b/nixpkgs/nixos/modules/services/misc/mautrix-telegram.nix
@@ -21,6 +21,7 @@ in {
         default = {
           appservice = rec {
             database = "sqlite:///${dataDir}/mautrix-telegram.db";
+            database_opts = {};
             hostname = "0.0.0.0";
             port = 8080;
             address = "http://localhost:${toString port}";
@@ -29,6 +30,8 @@ in {
           bridge = {
             permissions."*" = "relaybot";
             relaybot.whitelist = [ ];
+            double_puppet_server_map = {};
+            login_shared_secret_map = {};
           };
 
           logging = {
diff --git a/nixpkgs/nixos/modules/services/misc/mediatomb.nix b/nixpkgs/nixos/modules/services/misc/mediatomb.nix
index 529f584a201e..a19b73889ce4 100644
--- a/nixpkgs/nixos/modules/services/misc/mediatomb.nix
+++ b/nixpkgs/nixos/modules/services/misc/mediatomb.nix
@@ -6,37 +6,97 @@ let
 
   gid = config.ids.gids.mediatomb;
   cfg = config.services.mediatomb;
+  name = cfg.package.pname;
+  pkg = cfg.package;
+  optionYesNo = option: if option then "yes" else "no";
+  # configuration on media directory
+  mediaDirectory = {
+    options = {
+      path = mkOption {
+        type = types.str;
+        description = ''
+          Absolute directory path to the media directory to index.
+        '';
+      };
+      recursive = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether the indexation must take place recursively or not.";
+      };
+      hidden-files = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Whether to index the hidden files or not.";
+      };
+    };
+  };
+  toMediaDirectory = d: "<directory location=\"${d.path}\" mode=\"inotify\" recursive=\"${optionYesNo d.recursive}\" hidden-files=\"${optionYesNo d.hidden-files}\" />\n";
 
-  mtConf = pkgs.writeText "config.xml" ''
-  <?xml version="1.0" encoding="UTF-8"?>
-  <config version="2" xmlns="http://mediatomb.cc/config/2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://mediatomb.cc/config/2 http://mediatomb.cc/config/2.xsd">
+  transcodingConfig = if cfg.transcoding then with pkgs; ''
+    <transcoding enabled="yes">
+      <mimetype-profile-mappings>
+        <transcode mimetype="video/x-flv" using="vlcmpeg" />
+        <transcode mimetype="application/ogg" using="vlcmpeg" />
+        <transcode mimetype="audio/ogg" using="ogg2mp3" />
+        <transcode mimetype="audio/x-flac" using="oggflac2raw"/>
+      </mimetype-profile-mappings>
+      <profiles>
+        <profile name="ogg2mp3" enabled="no" type="external">
+          <mimetype>audio/mpeg</mimetype>
+          <accept-url>no</accept-url>
+          <first-resource>yes</first-resource>
+          <accept-ogg-theora>no</accept-ogg-theora>
+          <agent command="${ffmpeg}/bin/ffmpeg" arguments="-y -i %in -f mp3 %out" />
+          <buffer size="1048576" chunk-size="131072" fill-size="262144" />
+        </profile>
+        <profile name="vlcmpeg" enabled="no" type="external">
+          <mimetype>video/mpeg</mimetype>
+          <accept-url>yes</accept-url>
+          <first-resource>yes</first-resource>
+          <accept-ogg-theora>yes</accept-ogg-theora>
+          <agent command="${libsForQt5.vlc}/bin/vlc"
+            arguments="-I dummy %in --sout #transcode{venc=ffmpeg,vcodec=mp2v,vb=4096,fps=25,aenc=ffmpeg,acodec=mpga,ab=192,samplerate=44100,channels=2}:standard{access=file,mux=ps,dst=%out} vlc:quit" />
+          <buffer size="14400000" chunk-size="512000" fill-size="120000" />
+        </profile>
+      </profiles>
+    </transcoding>
+'' else ''
+    <transcoding enabled="no">
+    </transcoding>
+'';
+
+  configText = optionalString (! cfg.customCfg) ''
+<?xml version="1.0" encoding="UTF-8"?>
+<config version="2" xmlns="http://mediatomb.cc/config/2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://mediatomb.cc/config/2 http://mediatomb.cc/config/2.xsd">
     <server>
       <ui enabled="yes" show-tooltips="yes">
         <accounts enabled="no" session-timeout="30">
-          <account user="mediatomb" password="mediatomb"/>
+          <account user="${name}" password="${name}"/>
         </accounts>
       </ui>
       <name>${cfg.serverName}</name>
       <udn>uuid:${cfg.uuid}</udn>
       <home>${cfg.dataDir}</home>
-      <webroot>${pkgs.mediatomb}/share/mediatomb/web</webroot>
+      <interface>${cfg.interface}</interface>
+      <webroot>${pkg}/share/${name}/web</webroot>
+      <pc-directory upnp-hide="${optionYesNo cfg.pcDirectoryHide}"/>
       <storage>
         <sqlite3 enabled="yes">
-          <database-file>mediatomb.db</database-file>
+          <database-file>${name}.db</database-file>
         </sqlite3>
       </storage>
-      <protocolInfo extend="${if cfg.ps3Support then "yes" else "no"}"/>
-      ${if cfg.dsmSupport then ''
+      <protocolInfo extend="${optionYesNo cfg.ps3Support}"/>
+      ${optionalString cfg.dsmSupport ''
       <custom-http-headers>
         <add header="X-User-Agent: redsonic"/>
       </custom-http-headers>
 
       <manufacturerURL>redsonic.com</manufacturerURL>
       <modelNumber>105</modelNumber>
-      '' else ""}
-      ${if cfg.tg100Support then ''
+      ''}
+        ${optionalString cfg.tg100Support ''
       <upnp-string-limit>101</upnp-string-limit>
-      '' else ""}
+      ''}
       <extended-runtime-options>
         <mark-played-items enabled="yes" suppress-cds-updates="yes">
           <string mode="prepend">*</string>
@@ -47,11 +107,14 @@ let
       </extended-runtime-options>
     </server>
     <import hidden-files="no">
+      <autoscan use-inotify="auto">
+      ${concatMapStrings toMediaDirectory cfg.mediaDirectories}
+      </autoscan>
       <scripting script-charset="UTF-8">
-        <common-script>${pkgs.mediatomb}/share/mediatomb/js/common.js</common-script>
-        <playlist-script>${pkgs.mediatomb}/share/mediatomb/js/playlists.js</playlist-script>
+        <common-script>${pkg}/share/${name}/js/common.js</common-script>
+        <playlist-script>${pkg}/share/${name}/js/playlists.js</playlist-script>
         <virtual-layout type="builtin">
-          <import-script>${pkgs.mediatomb}/share/mediatomb/js/import.js</import-script>
+          <import-script>${pkg}/share/${name}/js/import.js</import-script>
         </virtual-layout>
       </scripting>
       <mappings>
@@ -75,12 +138,12 @@ let
           <map from="flv" to="video/x-flv"/>
           <map from="mkv" to="video/x-matroska"/>
           <map from="mka" to="audio/x-matroska"/>
-          ${if cfg.ps3Support then ''
+          ${optionalString cfg.ps3Support ''
           <map from="avi" to="video/divx"/>
-          '' else ""}
-          ${if cfg.dsmSupport then ''
+          ''}
+          ${optionalString cfg.dsmSupport ''
           <map from="avi" to="video/avi"/>
-          '' else ""}
+          ''}
         </extension-mimetype>
         <mimetype-upnpclass>
           <map from="audio/*" to="object.item.audioItem.musicTrack"/>
@@ -108,46 +171,27 @@ let
       </mappings>
       <online-content>
         <YouTube enabled="no" refresh="28800" update-at-start="no" purge-after="604800" racy-content="exclude" format="mp4" hd="no">
-          <favorites user="mediatomb"/>
+          <favorites user="${name}"/>
           <standardfeed feed="most_viewed" time-range="today"/>
-          <playlists user="mediatomb"/>
-          <uploads user="mediatomb"/>
+          <playlists user="${name}"/>
+          <uploads user="${name}"/>
           <standardfeed feed="recently_featured" time-range="today"/>
         </YouTube>
       </online-content>
     </import>
-    <transcoding enabled="${if cfg.transcoding then "yes" else "no"}">
-      <mimetype-profile-mappings>
-        <transcode mimetype="video/x-flv" using="vlcmpeg"/>
-        <transcode mimetype="application/ogg" using="vlcmpeg"/>
-        <transcode mimetype="application/ogg" using="oggflac2raw"/>
-        <transcode mimetype="audio/x-flac" using="oggflac2raw"/>
-      </mimetype-profile-mappings>
-      <profiles>
-        <profile name="oggflac2raw" enabled="no" type="external">
-          <mimetype>audio/L16</mimetype>
-          <accept-url>no</accept-url>
-          <first-resource>yes</first-resource>
-          <accept-ogg-theora>no</accept-ogg-theora>
-          <agent command="ogg123" arguments="-d raw -o byteorder:big -f %out %in"/>
-          <buffer size="1048576" chunk-size="131072" fill-size="262144"/>
-        </profile>
-        <profile name="vlcmpeg" enabled="no" type="external">
-          <mimetype>video/mpeg</mimetype>
-          <accept-url>yes</accept-url>
-          <first-resource>yes</first-resource>
-          <accept-ogg-theora>yes</accept-ogg-theora>
-          <agent command="vlc" arguments="-I dummy %in --sout #transcode{venc=ffmpeg,vcodec=mp2v,vb=4096,fps=25,aenc=ffmpeg,acodec=mpga,ab=192,samplerate=44100,channels=2}:standard{access=file,mux=ps,dst=%out} vlc:quit"/>
-          <buffer size="14400000" chunk-size="512000" fill-size="120000"/>
-        </profile>
-      </profiles>
-    </transcoding>
+    ${transcodingConfig}
   </config>
-  '';
+'';
+  defaultFirewallRules = {
+    # udp 1900 port needs to be opened for SSDP (not configurable within
+    # mediatomb/gerbera) cf.
+    # http://docs.gerbera.io/en/latest/run.html?highlight=udp%20port#network-setup
+    allowedUDPPorts = [ 1900 cfg.port ];
+    allowedTCPPorts = [ cfg.port ];
+  };
 
 in {
 
-
   ###### interface
 
   options = {
@@ -158,18 +202,27 @@ in {
         type = types.bool;
         default = false;
         description = ''
-          Whether to enable the mediatomb DLNA server.
+          Whether to enable the Gerbera/Mediatomb DLNA server.
         '';
       };
 
       serverName = mkOption {
         type = types.str;
-        default = "mediatomb";
+        default = "Gerbera (Mediatomb)";
         description = ''
           How to identify the server on the network.
         '';
       };
 
+      package = mkOption {
+        type = types.package;
+        example = literalExample "pkgs.mediatomb";
+        default = pkgs.gerbera;
+        description = ''
+          Underlying package to be used with the module (default: pkgs.gerbera).
+        '';
+      };
+
       ps3Support = mkOption {
         type = types.bool;
         default = false;
@@ -206,23 +259,34 @@ in {
 
       dataDir = mkOption {
         type = types.path;
-        default = "/var/lib/mediatomb";
+        default = "/var/lib/${name}";
         description = ''
-          The directory where mediatomb stores its state, data, etc.
+          The directory where Gerbera/Mediatomb stores its state, data, etc.
+        '';
+      };
+
+      pcDirectoryHide = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to list the top-level directory or not (from upnp client standpoint).
         '';
       };
 
       user = mkOption {
+        type = types.str;
         default = "mediatomb";
-        description = "User account under which mediatomb runs.";
+        description = "User account under which ${name} runs.";
       };
 
       group = mkOption {
+        type = types.str;
         default = "mediatomb";
-        description = "Group account under which mediatomb runs.";
+        description = "Group account under which ${name} runs.";
       };
 
       port = mkOption {
+        type = types.int;
         default = 49152;
         description = ''
           The network port to listen on.
@@ -230,40 +294,76 @@ in {
       };
 
       interface = mkOption {
+        type = types.str;
         default = "";
         description = ''
           A specific interface to bind to.
         '';
       };
 
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If false (the default), this is up to the user to declare the firewall rules.
+          If true, this opens port 1900 (tcp and udp) and the port specified by
+          <option>sercvices.mediatomb.port</option>.
+
+          If the option <option>services.mediatomb.interface</option> is set,
+          the firewall rules opened are dedicated to that interface. Otherwise,
+          those rules are opened globally.
+        '';
+      };
+
       uuid = mkOption {
+        type = types.str;
         default = "fdfc8a4e-a3ad-4c1d-b43d-a2eedb03a687";
         description = ''
           A unique (on your network) to identify the server by.
         '';
       };
 
+      mediaDirectories = mkOption {
+        type = with types; listOf (submodule mediaDirectory);
+        default = {};
+        description = ''
+          Declare media directories to index.
+        '';
+        example = [
+          { path = "/data/pictures"; recursive = false; hidden-files = false; }
+          { path = "/data/audio"; recursive = true; hidden-files = false; }
+        ];
+      };
+
       customCfg = mkOption {
         type = types.bool;
         default = false;
         description = ''
-          Allow mediatomb to create and use its own config file inside ${cfg.dataDir}.
+          Allow ${name} to create and use its own config file inside the <literal>dataDir</literal> as
+          configured by <option>services.mediatomb.dataDir</option>.
+          Deactivated by default, the service then runs with the configuration generated from this module.
+          Otherwise, when enabled, no service configuration is generated. Gerbera/Mediatomb then starts using
+          config.xml within the configured <literal>dataDir</literal>. It's up to the user to make a correct
+          configuration file.
         '';
       };
+
     };
   };
 
 
   ###### implementation
 
-  config = mkIf cfg.enable {
+  config = let binaryCommand = "${pkg}/bin/${name}";
+               interfaceFlag = optionalString ( cfg.interface != "") "--interface ${cfg.interface}";
+               configFlag = optionalString (! cfg.customCfg) "--config ${pkgs.writeText "config.xml" configText}";
+    in mkIf cfg.enable {
     systemd.services.mediatomb = {
-      description = "MediaTomb media Server";
+      description = "${cfg.serverName} media Server";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.mediatomb ];
-      serviceConfig.ExecStart = "${pkgs.mediatomb}/bin/mediatomb -p ${toString cfg.port} ${if cfg.interface!="" then "-e ${cfg.interface}" else ""} ${if cfg.customCfg then "" else "-c ${mtConf}"} -m ${cfg.dataDir}";
-      serviceConfig.User = "${cfg.user}";
+      serviceConfig.ExecStart = "${binaryCommand} --port ${toString cfg.port} ${interfaceFlag} ${configFlag} --home ${cfg.dataDir}";
+      serviceConfig.User = cfg.user;
     };
 
     users.groups = optionalAttrs (cfg.group == "mediatomb") {
@@ -274,15 +374,18 @@ in {
       mediatomb = {
         isSystemUser = true;
         group = cfg.group;
-        home = "${cfg.dataDir}";
+        home = cfg.dataDir;
         createHome = true;
-        description = "Mediatomb DLNA Server User";
+        description = "${name} DLNA Server User";
       };
     };
 
-    networking.firewall = {
-      allowedUDPPorts = [ 1900 cfg.port ];
-      allowedTCPPorts = [ cfg.port ];
-    };
+    # Open firewall only if users enable it
+    networking.firewall = mkMerge [
+      (mkIf (cfg.openFirewall && cfg.interface != "") {
+        interfaces."${cfg.interface}" = defaultFirewallRules;
+      })
+      (mkIf (cfg.openFirewall && cfg.interface == "") defaultFirewallRules)
+    ];
   };
 }
diff --git a/nixpkgs/nixos/modules/services/misc/n8n.nix b/nixpkgs/nixos/modules/services/misc/n8n.nix
new file mode 100644
index 000000000000..516d0f70ef0b
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/misc/n8n.nix
@@ -0,0 +1,78 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.n8n;
+  format = pkgs.formats.json {};
+  configFile = format.generate "n8n.json" cfg.settings;
+in
+{
+  options.services.n8n = {
+
+    enable = mkEnableOption "n8n server";
+
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Open ports in the firewall for the n8n web interface.";
+    };
+
+    settings = mkOption {
+      type = format.type;
+      default = {};
+      description = ''
+        Configuration for n8n, see <link xlink:href="https://docs.n8n.io/reference/configuration.html"/>
+        for supported values.
+      '';
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+    services.n8n.settings = {
+      # We use this to open the firewall, so we need to know about the default at eval time
+      port = lib.mkDefault 5678;
+    };
+
+    systemd.services.n8n = {
+      description = "N8N service";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      environment = {
+        # This folder must be writeable as the application is storing
+        # its data in it, so the StateDirectory is a good choice
+        N8N_USER_FOLDER = "/var/lib/n8n";
+        N8N_CONFIG_FILES = "${configFile}";
+      };
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = "${pkgs.n8n}/bin/n8n";
+        Restart = "on-failure";
+        StateDirectory = "n8n";
+
+        # Basic Hardening
+        NoNewPrivileges = "yes";
+        PrivateTmp = "yes";
+        PrivateDevices = "yes";
+        DevicePolicy = "closed";
+        DynamicUser = "true";
+        ProtectSystem = "strict";
+        ProtectHome = "read-only";
+        ProtectControlGroups = "yes";
+        ProtectKernelModules = "yes";
+        ProtectKernelTunables = "yes";
+        RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
+        RestrictNamespaces = "yes";
+        RestrictRealtime = "yes";
+        RestrictSUIDSGID = "yes";
+        MemoryDenyWriteExecute = "yes";
+        LockPersonality = "yes";
+      };
+    };
+
+    networking.firewall = mkIf cfg.openFirewall {
+      allowedTCPPorts = [ cfg.settings.port ];
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/misc/nix-daemon.nix b/nixpkgs/nixos/modules/services/misc/nix-daemon.nix
index 2680b1cc0d3b..0eeff31d6c4d 100644
--- a/nixpkgs/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixpkgs/nixos/modules/services/misc/nix-daemon.nix
@@ -45,7 +45,7 @@ let
         trusted-substituters = ${toString cfg.trustedBinaryCaches}
         trusted-public-keys = ${toString cfg.binaryCachePublicKeys}
         auto-optimise-store = ${boolToString cfg.autoOptimiseStore}
-        require-sigs = ${if cfg.requireSignedBinaryCaches then "true" else "false"}
+        require-sigs = ${boolToString cfg.requireSignedBinaryCaches}
         trusted-users = ${toString cfg.trustedUsers}
         allowed-users = ${toString cfg.allowedUsers}
         ${optionalString (!cfg.distributedBuilds) ''
@@ -539,7 +539,7 @@ in
     systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ];
 
     systemd.services.nix-daemon =
-      { path = [ nix pkgs.utillinux config.programs.ssh.package ]
+      { path = [ nix pkgs.util-linux config.programs.ssh.package ]
           ++ optionals cfg.distributedBuilds [ pkgs.gzip ];
 
         environment = cfg.envVars
diff --git a/nixpkgs/nixos/modules/services/misc/octoprint.nix b/nixpkgs/nixos/modules/services/misc/octoprint.nix
index e2fbd3b401cc..a69e65073050 100644
--- a/nixpkgs/nixos/modules/services/misc/octoprint.nix
+++ b/nixpkgs/nixos/modules/services/misc/octoprint.nix
@@ -68,7 +68,7 @@ in
       plugins = mkOption {
         default = plugins: [];
         defaultText = "plugins: []";
-        example = literalExample "plugins: with plugins; [ m33-fio stlviewer ]";
+        example = literalExample "plugins: with plugins; [ themeify stlviewer ]";
         description = "Additional plugins to be used. Available plugins are passed through the plugins input.";
       };
 
diff --git a/nixpkgs/nixos/modules/services/misc/safeeyes.nix b/nixpkgs/nixos/modules/services/misc/safeeyes.nix
index 6ecb0d13187c..1e748195e41a 100644
--- a/nixpkgs/nixos/modules/services/misc/safeeyes.nix
+++ b/nixpkgs/nixos/modules/services/misc/safeeyes.nix
@@ -32,14 +32,14 @@ in
       wantedBy = [ "graphical-session.target" ];
       partOf   = [ "graphical-session.target" ];
 
+      startLimitIntervalSec = 350;
+      startLimitBurst = 10;
       serviceConfig = {
         ExecStart = ''
           ${pkgs.safeeyes}/bin/safeeyes
         '';
         Restart = "on-failure";
         RestartSec = 3;
-        StartLimitInterval = 350;
-        StartLimitBurst = 10;
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/misc/siproxd.nix b/nixpkgs/nixos/modules/services/misc/siproxd.nix
index 0e87fc461d3f..20fe0793b84b 100644
--- a/nixpkgs/nixos/modules/services/misc/siproxd.nix
+++ b/nixpkgs/nixos/modules/services/misc/siproxd.nix
@@ -39,7 +39,7 @@ in
         default = false;
         description = ''
           Whether to enable the Siproxd SIP
-	  proxy/masquerading daemon.
+          proxy/masquerading daemon.
         '';
       };
 
@@ -57,29 +57,29 @@ in
 
       hostsAllowReg = mkOption {
         type = types.listOf types.str;
-	default = [ ];
+        default = [ ];
         example = [ "192.168.1.0/24" "192.168.2.0/24" ];
-	description = ''
+        description = ''
           Acess control list for incoming SIP registrations.
         '';
       };
 
       hostsAllowSip = mkOption {
         type = types.listOf types.str;
-	default = [ ];
+        default = [ ];
         example = [ "123.45.0.0/16" "123.46.0.0/16" ];
-	description = ''
+        description = ''
           Acess control list for incoming SIP traffic.
         '';
       };
 
       hostsDenySip = mkOption {
         type = types.listOf types.str;
-	default = [ ];
+        default = [ ];
         example = [ "10.0.0.0/8" "11.0.0.0/8" ];
-	description = ''
+        description = ''
           Acess control list for denying incoming
-	   SIP registrations and traffic.
+          SIP registrations and traffic.
         '';
       };
 
@@ -87,7 +87,7 @@ in
         type = types.int;
         default = 5060;
         description = ''
-	  Port to listen for incoming SIP messages.
+          Port to listen for incoming SIP messages.
         '';
       };
 
diff --git a/nixpkgs/nixos/modules/services/misc/snapper.nix b/nixpkgs/nixos/modules/services/misc/snapper.nix
index 6f3aaa973a04..3560d08520b7 100644
--- a/nixpkgs/nixos/modules/services/misc/snapper.nix
+++ b/nixpkgs/nixos/modules/services/misc/snapper.nix
@@ -121,6 +121,16 @@ in
 
     services.dbus.packages = [ pkgs.snapper ];
 
+    systemd.services.snapperd = {
+      description = "DBus interface for snapper";
+      inherit documentation;
+      serviceConfig = {
+        Type = "dbus";
+        BusName = "org.opensuse.Snapper";
+        ExecStart = "${pkgs.snapper}/bin/snapperd";
+      };
+    };
+
     systemd.services.snapper-timeline = {
       description = "Timeline of Snapper Snapshots";
       inherit documentation;
diff --git a/nixpkgs/nixos/modules/services/misc/ssm-agent.nix b/nixpkgs/nixos/modules/services/misc/ssm-agent.nix
index 00e806695fd5..e50b07e0b862 100644
--- a/nixpkgs/nixos/modules/services/misc/ssm-agent.nix
+++ b/nixpkgs/nixos/modules/services/misc/ssm-agent.nix
@@ -29,8 +29,6 @@ in {
 
   config = mkIf cfg.enable {
     systemd.services.ssm-agent = {
-      users.extraUsers.ssm-user = {};
-
       inherit (cfg.package.meta) description;
       after    = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
@@ -43,5 +41,26 @@ in {
         RestartSec = "15min";
       };
     };
+
+    # Add user that Session Manager needs, and give it sudo.
+    # This is consistent with Amazon Linux 2 images.
+    security.sudo.extraRules = [
+      {
+        users = [ "ssm-user" ];
+        commands = [
+          {
+            command = "ALL";
+            options = [ "NOPASSWD" ];
+          }
+        ];
+      }
+    ];
+    # On Amazon Linux 2 images, the ssm-user user is pretty much a
+    # normal user with its own group. We do the same.
+    users.groups.ssm-user = {};
+    users.users.ssm-user = {
+      isNormalUser = true;
+      group = "ssm-user";
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/misc/svnserve.nix b/nixpkgs/nixos/modules/services/misc/svnserve.nix
index 3335ed09d40e..f70e3ca7fef0 100644
--- a/nixpkgs/nixos/modules/services/misc/svnserve.nix
+++ b/nixpkgs/nixos/modules/services/misc/svnserve.nix
@@ -25,7 +25,7 @@ in
 
       svnBaseDir = mkOption {
         default = "/repos";
-	description = "Base directory from which Subversion repositories are accessed.";
+        description = "Base directory from which Subversion repositories are accessed.";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix b/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix
index 0957920f1a09..cd987eb76c76 100644
--- a/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix
+++ b/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix
@@ -70,6 +70,7 @@ in
       description = "Zigbee2mqtt Service";
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
+      environment.ZIGBEE2MQTT_DATA = cfg.dataDir;
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/zigbee2mqtt";
         User = "zigbee2mqtt";
diff --git a/nixpkgs/nixos/modules/services/misc/zookeeper.nix b/nixpkgs/nixos/modules/services/misc/zookeeper.nix
index f6af7c75ebae..1d12e81a9eca 100644
--- a/nixpkgs/nixos/modules/services/misc/zookeeper.nix
+++ b/nixpkgs/nixos/modules/services/misc/zookeeper.nix
@@ -76,6 +76,7 @@ in {
       default = ''
         zookeeper.root.logger=INFO, CONSOLE
         log4j.rootLogger=INFO, CONSOLE
+        log4j.logger.org.apache.zookeeper.audit.Log4jAuditLogger=INFO, CONSOLE
         log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
         log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
         log4j.appender.CONSOLE.layout.ConversionPattern=[myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n
@@ -128,11 +129,10 @@ in {
       description = "Zookeeper Daemon";
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
-      environment = { ZOOCFGDIR = configDir; };
       serviceConfig = {
         ExecStart = ''
           ${pkgs.jre}/bin/java \
-            -cp "${cfg.package}/lib/*:${cfg.package}/${cfg.package.name}.jar:${configDir}" \
+            -cp "${cfg.package}/lib/*:${configDir}" \
             ${escapeShellArgs cfg.extraCmdLineOptions} \
             -Dzookeeper.datadir.autocreate=false \
             ${optionalString cfg.preferIPv4 "-Djava.net.preferIPv4Stack=true"} \
@@ -143,6 +143,7 @@ in {
       };
       preStart = ''
         echo "${toString cfg.id}" > ${cfg.dataDir}/myid
+        mkdir -p ${cfg.dataDir}/version-2
       '';
     };
 
diff --git a/nixpkgs/nixos/modules/services/monitoring/grafana-image-renderer.nix b/nixpkgs/nixos/modules/services/monitoring/grafana-image-renderer.nix
new file mode 100644
index 000000000000..a010a5316bae
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/grafana-image-renderer.nix
@@ -0,0 +1,150 @@
+{ lib, pkgs, config, ... }:
+
+with lib;
+
+let
+  cfg = config.services.grafana-image-renderer;
+
+  format = pkgs.formats.json { };
+
+  configFile = format.generate "grafana-image-renderer-config.json" cfg.settings;
+in {
+  options.services.grafana-image-renderer = {
+    enable = mkEnableOption "grafana-image-renderer";
+
+    chromium = mkOption {
+      type = types.package;
+      description = ''
+        The chromium to use for image rendering.
+      '';
+    };
+
+    verbose = mkEnableOption "verbosity for the service";
+
+    provisionGrafana = mkEnableOption "Grafana configuration for grafana-image-renderer";
+
+    settings = mkOption {
+      type = types.submodule {
+        freeformType = format.type;
+
+        options = {
+          service = {
+            port = mkOption {
+              type = types.port;
+              default = 8081;
+              description = ''
+                The TCP port to use for the rendering server.
+              '';
+            };
+            logging.level = mkOption {
+              type = types.enum [ "error" "warning" "info" "debug" ];
+              default = "info";
+              description = ''
+                The log-level of the <filename>grafana-image-renderer.service</filename>-unit.
+              '';
+            };
+          };
+          rendering = {
+            width = mkOption {
+              default = 1000;
+              type = types.ints.positive;
+              description = ''
+                Width of the PNG used to display the alerting graph.
+              '';
+            };
+            height = mkOption {
+              default = 500;
+              type = types.ints.positive;
+              description = ''
+                Height of the PNG used to display the alerting graph.
+              '';
+            };
+            mode = mkOption {
+              default = "default";
+              type = types.enum [ "default" "reusable" "clustered" ];
+              description = ''
+                Rendering mode of <package>grafana-image-renderer</package>:
+                <itemizedlist>
+                <listitem><para><literal>default:</literal> Creates on browser-instance
+                  per rendering request.</para></listitem>
+                <listitem><para><literal>reusable:</literal> One browser instance
+                  will be started and reused for each rendering request.</para></listitem>
+                <listitem><para><literal>clustered:</literal> allows to precisely
+                  configure how many browser-instances are supposed to be used. The values
+                  for that mode can be declared in <literal>rendering.clustering</literal>.
+                  </para></listitem>
+                </itemizedlist>
+              '';
+            };
+            args = mkOption {
+              type = types.listOf types.str;
+              default = [ "--no-sandbox" ];
+              description = ''
+                List of CLI flags passed to <package>chromium</package>.
+              '';
+            };
+          };
+        };
+      };
+
+      default = {};
+
+      description = ''
+        Configuration attributes for <package>grafana-image-renderer</package>.
+
+        See <link xlink:href="https://github.com/grafana/grafana-image-renderer/blob/ce1f81438e5f69c7fd7c73ce08bab624c4c92e25/default.json" />
+        for supported values.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    assertions = [
+      { assertion = cfg.provisionGrafana -> config.services.grafana.enable;
+        message = ''
+          To provision a Grafana instance to use grafana-image-renderer,
+          `services.grafana.enable` must be set to `true`!
+        '';
+      }
+    ];
+
+    services.grafana.extraOptions = mkIf cfg.provisionGrafana {
+      RENDERING_SERVER_URL = "http://localhost:${toString cfg.settings.service.port}/render";
+      RENDERING_CALLBACK_URL = "http://localhost:${toString config.services.grafana.port}";
+    };
+
+    services.grafana-image-renderer.chromium = mkDefault pkgs.chromium;
+
+    services.grafana-image-renderer.settings = {
+      rendering = mapAttrs (const mkDefault) {
+        chromeBin = "${cfg.chromium}/bin/chromium";
+        verboseLogging = cfg.verbose;
+        timezone = config.time.timeZone;
+      };
+
+      services = {
+        logging.level = mkIf cfg.verbose (mkDefault "debug");
+        metrics.enabled = mkDefault false;
+      };
+    };
+
+    systemd.services.grafana-image-renderer = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      description = " A Grafana backend plugin that handles rendering of panels & dashboards to PNGs using headless browser (Chromium/Chrome)";
+
+      environment = {
+        PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = "true";
+      };
+
+      serviceConfig = {
+        DynamicUser = true;
+        PrivateTmp = true;
+        ExecStart = "${pkgs.grafana-image-renderer}/bin/grafana-image-renderer server --config=${configFile}";
+        Restart = "always";
+      };
+    };
+  };
+
+  meta.maintainers = with maintainers; [ ma27 ];
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/grafana.nix b/nixpkgs/nixos/modules/services/monitoring/grafana.nix
index b0c81a46d4d8..c8515c4b8988 100644
--- a/nixpkgs/nixos/modules/services/monitoring/grafana.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/grafana.nix
@@ -5,10 +5,11 @@ with lib;
 let
   cfg = config.services.grafana;
   opt = options.services.grafana;
+  declarativePlugins = pkgs.linkFarm "grafana-plugins" (builtins.map (pkg: { name = pkg.pname; path = pkg; }) cfg.declarativePlugins);
 
   envOptions = {
     PATHS_DATA = cfg.dataDir;
-    PATHS_PLUGINS = "${cfg.dataDir}/plugins";
+    PATHS_PLUGINS = if builtins.isNull cfg.declarativePlugins then "${cfg.dataDir}/plugins" else declarativePlugins;
     PATHS_LOGS = "${cfg.dataDir}/log";
 
     SERVER_PROTOCOL = cfg.protocol;
@@ -260,6 +261,12 @@ in {
       defaultText = "pkgs.grafana";
       type = types.package;
     };
+    declarativePlugins = mkOption {
+      type = with types; nullOr (listOf path);
+      default = null;
+      description = "If non-null, then a list of packages containing Grafana plugins to install. If set, plugins cannot be manually installed.";
+      example = literalExample "with pkgs.grafanaPlugins; [ grafana-piechart-panel ]";
+    };
 
     dataDir = mkOption {
       description = "Data directory.";
diff --git a/nixpkgs/nixos/modules/services/monitoring/loki.nix b/nixpkgs/nixos/modules/services/monitoring/loki.nix
index f4eec7e0d284..51cabaa274a3 100644
--- a/nixpkgs/nixos/modules/services/monitoring/loki.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/loki.nix
@@ -39,7 +39,7 @@ in {
     };
 
     configuration = mkOption {
-      type = types.attrs;
+      type = (pkgs.formats.json {}).type;
       default = {};
       description = ''
         Specify the configuration for Loki in Nix.
@@ -78,6 +78,8 @@ in {
       '';
     }];
 
+    environment.systemPackages = [ pkgs.grafana-loki ]; # logcli
+
     users.groups.${cfg.group} = { };
     users.users.${cfg.user} = {
       description = "Loki Service User";
diff --git a/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix b/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix
new file mode 100644
index 000000000000..7046de9d403c
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix
@@ -0,0 +1,111 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.mackerel-agent;
+  settingsFmt = pkgs.formats.toml {};
+in {
+  options.services.mackerel-agent = {
+    enable = mkEnableOption "mackerel.io agent";
+
+    # the upstream package runs as root, but doesn't seem to be strictly
+    # necessary for basic functionality
+    runAsRoot = mkEnableOption "Whether to run as root.";
+
+    autoRetirement = mkEnableOption ''
+      Whether to automatically retire the host upon OS shutdown.
+    '';
+
+    apiKeyFile = mkOption {
+      type = types.path;
+      default = "";
+      example = "/run/keys/mackerel-api-key";
+      description = ''
+        Path to file containing the Mackerel API key. The file should contain a
+        single line of the following form:
+
+        <literallayout>apikey = "EXAMPLE_API_KEY"</literallayout>
+      '';
+    };
+
+    settings = mkOption {
+      description = ''
+        Options for mackerel-agent.conf.
+
+        Documentation:
+        <link xlink:href="https://mackerel.io/docs/entry/spec/agent"/>
+      '';
+
+      default = {};
+      example = {
+        verbose = false;
+        silent = false;
+      };
+
+      type = types.submodule {
+        freeformType = settingsFmt.type;
+
+        options.host_status = {
+          on_start = mkOption {
+            type = types.enum [ "working" "standby" "maintenance" "poweroff" ];
+            description = "Host status after agent startup.";
+            default = "working";
+          };
+          on_stop = mkOption {
+            type = types.enum [ "working" "standby" "maintenance" "poweroff" ];
+            description = "Host status after agent shutdown.";
+            default = "poweroff";
+          };
+        };
+
+        options.diagnostic =
+          mkEnableOption "Collect memory usage for the agent itself";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = with pkgs; [ mackerel-agent ];
+
+    environment.etc = {
+      "mackerel-agent/mackerel-agent.conf".source =
+        settingsFmt.generate "mackerel-agent.conf" cfg.settings;
+      "mackerel-agent/conf.d/api-key.conf".source = cfg.apiKeyFile;
+    };
+
+    services.mackerel-agent.settings = {
+      root = mkDefault "/var/lib/mackerel-agent";
+      pidfile = mkDefault "/run/mackerel-agent/mackerel-agent.pid";
+
+      # conf.d stores the symlink to cfg.apiKeyFile
+      include = mkDefault "/etc/mackerel-agent/conf.d/*.conf";
+    };
+
+    # upstream service file in https://git.io/JUt4Q
+    systemd.services.mackerel-agent = {
+      description = "mackerel.io agent";
+      after = [ "network-online.target" "nss-lookup.target" ];
+      wantedBy = [ "multi-user.target" ];
+      environment = {
+        MACKEREL_PLUGIN_WORKDIR = mkDefault "%C/mackerel-agent";
+      };
+      serviceConfig = {
+        DynamicUser = !cfg.runAsRoot;
+        PrivateTmp = mkDefault true;
+        CacheDirectory = "mackerel-agent";
+        ConfigurationDirectory = "mackerel-agent";
+        RuntimeDirectory = "mackerel-agent";
+        StateDirectory = "mackerel-agent";
+        ExecStart = "${pkgs.mackerel-agent}/bin/mackerel-agent supervise";
+        ExecStopPost = mkIf cfg.autoRetirement "${pkg.mackerel-agent}/bin/mackerel-agent retire -force";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        LimitNOFILE = mkDefault 65536;
+        LimitNPROC = mkDefault 65536;
+      };
+      restartTriggers = [
+        config.environment.etc."mackerel-agent/mackerel-agent.conf".source
+      ];
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/netdata.nix b/nixpkgs/nixos/modules/services/monitoring/netdata.nix
index 2e73e15d3a86..db51fdbd2c61 100644
--- a/nixpkgs/nixos/modules/services/monitoring/netdata.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/netdata.nix
@@ -142,7 +142,7 @@ in {
       serviceConfig = {
         Environment="PYTHONPATH=${cfg.package}/libexec/netdata/python.d/python_modules";
         ExecStart = "${cfg.package}/bin/netdata -P /run/netdata/netdata.pid -D -c ${configFile}";
-        ExecReload = "${pkgs.utillinux}/bin/kill -s HUP -s USR1 -s USR2 $MAINPID";
+        ExecReload = "${pkgs.util-linux}/bin/kill -s HUP -s USR1 -s USR2 $MAINPID";
         TimeoutStopSec = 60;
         Restart = "on-failure";
         # User and group
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
index 98aaa9c0f030..4f9be38f7f14 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
@@ -32,6 +32,8 @@ let
       (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules))
     ]);
     scrape_configs = filterValidPrometheus cfg.scrapeConfigs;
+    remote_write = filterValidPrometheus cfg.remoteWrite;
+    remote_read = filterValidPrometheus cfg.remoteRead;
     alerting = {
       inherit (cfg) alertmanagers;
     };
@@ -45,7 +47,7 @@ let
 
   cmdlineArgs = cfg.extraFlags ++ [
     "--storage.tsdb.path=${workingDir}/data/"
-    "--config.file=${prometheusYml}"
+    "--config.file=/run/prometheus/prometheus-substituted.yaml"
     "--web.listen-address=${cfg.listenAddress}:${builtins.toString cfg.port}"
     "--alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}"
     "--alertmanager.timeout=${toString cfg.alertmanagerTimeout}s"
@@ -101,6 +103,157 @@ let
     };
   };
 
+  promTypes.remote_read = types.submodule {
+    options = {
+      url = mkOption {
+        type = types.str;
+        description = ''
+          ServerName extension to indicate the name of the server.
+          http://tools.ietf.org/html/rfc4366#section-3.1
+        '';
+      };
+      name = mkOpt types.string ''
+        Name of the remote read config, which if specified must be unique among remote read configs.
+        The name will be used in metrics and logging in place of a generated value to help users distinguish between
+        remote read configs.
+      '';
+      required_matchers = mkOpt (types.attrsOf types.str) ''
+        An optional list of equality matchers which have to be
+        present in a selector to query the remote read endpoint.
+      '';
+      remote_timeout = mkOpt types.str ''
+        Timeout for requests to the remote read endpoint.
+      '';
+      read_recent = mkOpt types.bool ''
+        Whether reads should be made for queries for time ranges that
+        the local storage should have complete data for.
+      '';
+      basic_auth = mkOpt (types.submodule {
+        options = {
+          username = mkOption {
+            type = types.str;
+            description = ''
+              HTTP username
+            '';
+          };
+          password = mkOpt types.str "HTTP password";
+          password_file = mkOpt types.str "HTTP password file";
+        };
+      }) ''
+        Sets the `Authorization` header on every remote read request with the
+        configured username and password.
+        password and password_file are mutually exclusive.
+      '';
+      bearer_token = mkOpt types.str ''
+        Sets the `Authorization` header on every remote read request with
+        the configured bearer token. It is mutually exclusive with `bearer_token_file`.
+      '';
+      bearer_token_file = mkOpt types.str ''
+        Sets the `Authorization` header on every remote read request with the bearer token
+        read from the configured file. It is mutually exclusive with `bearer_token`.
+      '';
+      tls_config = mkOpt promTypes.tls_config ''
+        Configures the remote read request's TLS settings.
+      '';
+      proxy_url = mkOpt types.str "Optional Proxy URL.";
+    };
+  };
+
+  promTypes.remote_write = types.submodule {
+    options = {
+      url = mkOption {
+        type = types.str;
+        description = ''
+          ServerName extension to indicate the name of the server.
+          http://tools.ietf.org/html/rfc4366#section-3.1
+        '';
+      };
+      remote_timeout = mkOpt types.str ''
+        Timeout for requests to the remote write endpoint.
+      '';
+      write_relabel_configs = mkOpt (types.listOf promTypes.relabel_config) ''
+        List of remote write relabel configurations.
+      '';
+      name = mkOpt types.string ''
+        Name of the remote write config, which if specified must be unique among remote write configs.
+        The name will be used in metrics and logging in place of a generated value to help users distinguish between
+        remote write configs.
+      '';
+      basic_auth = mkOpt (types.submodule {
+        options = {
+          username = mkOption {
+            type = types.str;
+            description = ''
+              HTTP username
+            '';
+          };
+          password = mkOpt types.str "HTTP password";
+          password_file = mkOpt types.str "HTTP password file";
+        };
+      }) ''
+        Sets the `Authorization` header on every remote write request with the
+        configured username and password.
+        password and password_file are mutually exclusive.
+      '';
+      bearer_token = mkOpt types.str ''
+        Sets the `Authorization` header on every remote write request with
+        the configured bearer token. It is mutually exclusive with `bearer_token_file`.
+      '';
+      bearer_token_file = mkOpt types.str ''
+        Sets the `Authorization` header on every remote write request with the bearer token
+        read from the configured file. It is mutually exclusive with `bearer_token`.
+      '';
+      tls_config = mkOpt promTypes.tls_config ''
+        Configures the remote write request's TLS settings.
+      '';
+      proxy_url = mkOpt types.str "Optional Proxy URL.";
+      queue_config = mkOpt (types.submodule {
+        options = {
+          capacity = mkOpt types.int ''
+            Number of samples to buffer per shard before we block reading of more
+            samples from the WAL. It is recommended to have enough capacity in each
+            shard to buffer several requests to keep throughput up while processing
+            occasional slow remote requests.
+          '';
+          max_shards = mkOpt types.int ''
+            Maximum number of shards, i.e. amount of concurrency.
+          '';
+          min_shards = mkOpt types.int ''
+            Minimum number of shards, i.e. amount of concurrency.
+          '';
+          max_samples_per_send = mkOpt types.int ''
+            Maximum number of samples per send.
+          '';
+          batch_send_deadline = mkOpt types.str ''
+            Maximum time a sample will wait in buffer.
+          '';
+          min_backoff = mkOpt types.str ''
+            Initial retry delay. Gets doubled for every retry.
+          '';
+          max_backoff = mkOpt types.str ''
+            Maximum retry delay.
+          '';
+        };
+      }) ''
+        Configures the queue used to write to remote storage.
+      '';
+      metadata_config = mkOpt (types.submodule {
+        options = {
+          send = mkOpt types.bool ''
+            Whether metric metadata is sent to remote storage or not.
+          '';
+          send_interval = mkOpt types.str ''
+            How frequently metric metadata is sent to remote storage.
+          '';
+        };
+      }) ''
+        Configures the sending of series metadata to remote storage.
+        Metadata configuration is subject to change at any point
+        or be removed in future releases.
+      '';
+    };
+  };
+
   promTypes.scrape_config = types.submodule {
     options = {
       job_name = mkOption {
@@ -432,10 +585,10 @@ let
         regular expression matches.
       '';
 
-      action = mkDefOpt (types.enum ["replace" "keep" "drop"]) "replace" ''
+      action =
+        mkDefOpt (types.enum ["replace" "keep" "drop" "hashmod" "labelmap" "labeldrop" "labelkeep"]) "replace" ''
         Action to perform based on regex matching.
       '';
-
     };
   };
 
@@ -522,6 +675,45 @@ in {
       '';
     };
 
+    environmentFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      example = "/root/prometheus.env";
+      description = ''
+        Environment file as defined in <citerefentry>
+        <refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum>
+        </citerefentry>.
+
+        Secrets may be passed to the service without adding them to the
+        world-readable Nix store, by specifying placeholder variables as
+        the option value in Nix and setting these variables accordingly in the
+        environment file.
+
+        Environment variables from this file will be interpolated into the
+        config file using envsubst with this syntax:
+        <literal>$ENVIRONMENT ''${VARIABLE}</literal>
+
+        <programlisting>
+          # Example scrape config entry handling an OAuth bearer token
+          {
+            job_name = "home_assistant";
+            metrics_path = "/api/prometheus";
+            scheme = "https";
+            bearer_token = "\''${HOME_ASSISTANT_BEARER_TOKEN}";
+            [...]
+          }
+        </programlisting>
+
+        <programlisting>
+          # Content of the environment file
+          HOME_ASSISTANT_BEARER_TOKEN=someoauthbearertoken
+        </programlisting>
+
+        Note that this file needs to be available on the host on which
+        <literal>Prometheus</literal> is running.
+      '';
+    };
+
     configText = mkOption {
       type = types.nullOr types.lines;
       default = null;
@@ -541,6 +733,24 @@ in {
       '';
     };
 
+    remoteRead = mkOption {
+      type = types.listOf promTypes.remote_read;
+      default = [];
+      description = ''
+        Parameters of the endpoints to query from.
+        See <link xlink:href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_read">the official documentation</link> for more information.
+      '';
+    };
+
+    remoteWrite = mkOption {
+      type = types.listOf promTypes.remote_write;
+      default = [];
+      description = ''
+        Parameters of the endpoints to send samples to.
+        See <link xlink:href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write">the official documentation</link> for more information.
+      '';
+    };
+
     rules = mkOption {
       type = types.listOf types.str;
       default = [];
@@ -662,12 +872,19 @@ in {
     systemd.services.prometheus = {
       wantedBy = [ "multi-user.target" ];
       after    = [ "network.target" ];
+      preStart = ''
+         ${lib.getBin pkgs.envsubst}/bin/envsubst -o "/run/prometheus/prometheus-substituted.yaml" \
+                                                  -i "${prometheusYml}"
+      '';
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/prometheus" +
           optionalString (length cmdlineArgs != 0) (" \\\n  " +
             concatStringsSep " \\\n  " cmdlineArgs);
         User = "prometheus";
         Restart  = "always";
+        EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ];
+        RuntimeDirectory = "prometheus";
+        RuntimeDirectoryMode = "0700";
         WorkingDirectory = workingDir;
         StateDirectory = cfg.stateDir;
       };
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
index cc71451bf206..1fd85c66f843 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -23,6 +23,7 @@ let
   exporterOpts = genAttrs [
     "apcupsd"
     "bind"
+    "bird"
     "blackbox"
     "collectd"
     "dnsmasq"
@@ -37,12 +38,18 @@ let
     "modemmanager"
     "nextcloud"
     "nginx"
+    "nginxlog"
     "node"
+    "openvpn"
     "postfix"
     "postgres"
+    "py-air-control"
     "redis"
     "rspamd"
+    "rtl_433"
     "snmp"
+    "smokeping"
+    "sql"
     "surfboard"
     "tor"
     "unifi"
@@ -101,7 +108,6 @@ let
       default = "${name}-exporter";
       description = ''
         User name under which the ${name} exporter shall be run.
-        Has no effect when <option>systemd.services.prometheus-${name}-exporter.serviceConfig.DynamicUser</option> is true.
       '';
     };
     group = mkOption {
@@ -109,7 +115,6 @@ let
       default = "${name}-exporter";
       description = ''
         Group under which the ${name} exporter shall be run.
-        Has no effect when <option>systemd.services.prometheus-${name}-exporter.serviceConfig.DynamicUser</option> is true.
       '';
     };
   });
@@ -161,10 +166,9 @@ let
         serviceConfig.PrivateTmp = mkDefault true;
         serviceConfig.WorkingDirectory = mkDefault /tmp;
         serviceConfig.DynamicUser = mkDefault enableDynamicUser;
-      } serviceOpts ] ++ optional (!enableDynamicUser) {
         serviceConfig.User = conf.user;
         serviceConfig.Group = conf.group;
-      });
+      } serviceOpts ]);
   };
 in
 {
@@ -219,16 +223,26 @@ in
         Please specify either 'services.prometheus.exporters.mail.configuration'
           or 'services.prometheus.exporters.mail.configFile'.
       '';
+    } {
+      assertion = cfg.sql.enable -> (
+        (cfg.sql.configFile == null) != (cfg.sql.configuration == null)
+      );
+      message = ''
+        Please specify either 'services.prometheus.exporters.sql.configuration' or
+          'services.prometheus.exporters.sql.configFile'
+      '';
     } ];
   }] ++ [(mkIf config.services.minio.enable {
     services.prometheus.exporters.minio.minioAddress  = mkDefault "http://localhost:9000";
     services.prometheus.exporters.minio.minioAccessKey = mkDefault config.services.minio.accessKey;
     services.prometheus.exporters.minio.minioAccessSecret = mkDefault config.services.minio.secretKey;
-  })] ++ [(mkIf config.services.rspamd.enable {
-    services.prometheus.exporters.rspamd.url = mkDefault "http://localhost:11334/stat";
+  })] ++ [(mkIf config.services.prometheus.exporters.rtl_433.enable {
+    hardware.rtl-sdr.enable = mkDefault true;
   })] ++ [(mkIf config.services.nginx.enable {
     systemd.services.prometheus-nginx-exporter.after = [ "nginx.service" ];
     systemd.services.prometheus-nginx-exporter.requires = [ "nginx.service" ];
+  })] ++ [(mkIf config.services.postfix.enable {
+    services.prometheus.exporters.postfix.group = mkDefault config.services.postfix.setgidGroup;
   })] ++ (mapAttrsToList (name: conf:
     mkExporterConf {
       inherit name;
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bird.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bird.nix
new file mode 100644
index 000000000000..d8a526eafcea
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bird.nix
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.bird;
+in
+{
+  port = 9324;
+  extraOpts = {
+    birdVersion = mkOption {
+      type = types.enum [ 1 2 ];
+      default = 2;
+      description = ''
+        Specifies whether BIRD1 or BIRD2 is in use.
+      '';
+    };
+    birdSocket = mkOption {
+      type = types.path;
+      default = "/var/run/bird.ctl";
+      description = ''
+        Path to BIRD2 (or BIRD1 v4) socket.
+      '';
+    };
+    newMetricFormat = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Enable the new more-generic metric format.
+      '';
+    };
+  };
+  serviceOpts = {
+    serviceConfig = {
+      SupplementaryGroups = singleton (if cfg.birdVersion == 1 then "bird" else "bird2");
+      ExecStart = ''
+        ${pkgs.prometheus-bird-exporter}/bin/bird_exporter \
+          -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          -bird.socket ${cfg.birdSocket} \
+          -bird.v2=${if cfg.birdVersion == 2 then "true" else "false"} \
+          -format.new=${if cfg.newMetricFormat then "true" else "false"} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix
index bd0026b55f72..1800da69a255 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix
@@ -8,28 +8,36 @@ in
 {
   port = 7979;
   extraOpts = {
-    url = mkOption {
-      type = types.str;
-      description = ''
-        URL to scrape JSON from.
-      '';
-    };
     configFile = mkOption {
       type = types.path;
       description = ''
         Path to configuration file.
       '';
     };
-    listenAddress = {}; # not used
   };
   serviceOpts = {
     serviceConfig = {
       ExecStart = ''
-        ${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \
-          --port ${toString cfg.port} \
-          ${cfg.url} ${escapeShellArg cfg.configFile} \
+        ${pkgs.prometheus-json-exporter}/bin/json_exporter \
+          --config.file ${escapeShellArg cfg.configFile} \
+          --web.listen-address="${cfg.listenAddress}:${toString cfg.port}" \
           ${concatStringsSep " \\\n  " cfg.extraFlags}
       '';
     };
   };
+  imports = [
+    (mkRemovedOptionModule [ "url" ] ''
+      This option was removed. The URL of the endpoint serving JSON
+      must now be provided to the exporter by prometheus via the url
+      parameter `target'.
+
+      In prometheus a scrape URL would look like this:
+
+        http://some.json-exporter.host:7979/probe?target=https://example.com/some/json/endpoint
+
+      For more information, take a look at the official documentation
+      (https://github.com/prometheus-community/json_exporter) of the json_exporter.
+    '')
+     ({ options.warnings = options.warnings; options.assertions = options.assertions; })
+  ];
 }
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginxlog.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginxlog.nix
new file mode 100644
index 000000000000..8c1f552d58a7
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginxlog.nix
@@ -0,0 +1,51 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.nginxlog;
+in {
+  port = 9117;
+  extraOpts = {
+    settings = mkOption {
+      type = types.attrs;
+      default = {};
+      description = ''
+        All settings of nginxlog expressed as an Nix attrset.
+
+        Check the official documentation for the corresponding YAML
+        settings that can all be used here: https://github.com/martin-helmich/prometheus-nginxlog-exporter
+
+        The `listen` object is already generated by `port`, `listenAddress` and `metricsEndpoint` and
+        will be merged with the value of `settings` before writting it as JSON.
+      '';
+    };
+
+    metricsEndpoint = mkOption {
+      type = types.str;
+      default = "/metrics";
+      description = ''
+        Path under which to expose metrics.
+      '';
+    };
+  };
+
+  serviceOpts = let
+    listenConfig = {
+      listen = {
+        port = cfg.port;
+        address = cfg.listenAddress;
+        metrics_endpoint = cfg.metricsEndpoint;
+      };
+    };
+    completeConfig = pkgs.writeText "nginxlog-exporter.yaml" (builtins.toJSON (lib.recursiveUpdate listenConfig cfg.settings));
+  in {
+    serviceConfig = {
+      ExecStart = ''
+        ${pkgs.prometheus-nginxlog-exporter}/bin/prometheus-nginxlog-exporter -config-file ${completeConfig}
+      '';
+      Restart="always";
+      ProtectSystem="full";
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix
new file mode 100644
index 000000000000..a97a753ebc37
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix
@@ -0,0 +1,39 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.openvpn;
+in {
+  port = 9176;
+  extraOpts = {
+    statusPaths = mkOption {
+      type = types.listOf types.str;
+      description = ''
+        Paths to OpenVPN status files. Please configure the OpenVPN option
+        <literal>status</literal> accordingly.
+      '';
+    };
+    telemetryPath = mkOption {
+      type = types.str;
+      default = "/metrics";
+      description = ''
+        Path under which to expose metrics.
+      '';
+    };
+  };
+
+  serviceOpts = {
+    serviceConfig = {
+      PrivateDevices = true;
+      ProtectKernelModules = true;
+      NoNewPrivileges = true;
+      ExecStart = ''
+        ${pkgs.prometheus-openvpn-exporter}/bin/openvpn_exporter \
+          -openvpn.status_paths "${concatStringsSep "," cfg.statusPaths}" \
+          -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          -web.telemetry-path ${cfg.telemetryPath}
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix
index 3b6ef1631f89..f57589a59c7b 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix
@@ -8,6 +8,15 @@ in
 {
   port = 9154;
   extraOpts = {
+    group = mkOption {
+      type = types.str;
+      description = ''
+        Group under which the postfix exporter shall be run.
+        It should match the group that is allowed to access the
+        <literal>showq</literal> socket in the <literal>queue/public/</literal> directory.
+        Defaults to <literal>services.postfix.setgidGroup</literal> when postfix is enabled.
+      '';
+    };
     telemetryPath = mkOption {
       type = types.str;
       default = "/metrics";
@@ -26,16 +35,20 @@ in
     };
     showqPath = mkOption {
       type = types.path;
-      default = "/var/spool/postfix/public/showq";
-      example = "/var/lib/postfix/queue/public/showq";
+      default = "/var/lib/postfix/queue/public/showq";
+      example = "/var/spool/postfix/public/showq";
       description = ''
-        Path where Postfix places it's showq socket.
+        Path where Postfix places its showq socket.
       '';
     };
     systemd = {
-      enable = mkEnableOption ''
-        reading metrics from the systemd-journal instead of from a logfile
-      '';
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to enable reading metrics from the systemd journal instead of from a logfile
+        '';
+      };
       unit = mkOption {
         type = types.str;
         default = "postfix.service";
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/py-air-control.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/py-air-control.nix
new file mode 100644
index 000000000000..d9ab99221d9d
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/py-air-control.nix
@@ -0,0 +1,53 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.py-air-control;
+
+  workingDir = "/var/lib/${cfg.stateDir}";
+
+in
+{
+  port = 9896;
+  extraOpts = {
+    deviceHostname = mkOption {
+      type = types.str;
+      example = "192.168.1.123";
+      description = ''
+        The hostname of the air purification device from which to scrape the metrics.
+      '';
+    };
+    protocol = mkOption {
+      type = types.str;
+      default = "http";
+      description = ''
+        The protocol to use when communicating with the air purification device.
+        Available: [http, coap, plain_coap]
+      '';
+    };
+    stateDir = mkOption {
+      type = types.str;
+      default = "prometheus-py-air-control-exporter";
+      description = ''
+        Directory below <literal>/var/lib</literal> to store runtime data.
+        This directory will be created automatically using systemd's StateDirectory mechanism.
+      '';
+    };
+  };
+  serviceOpts = {
+    serviceConfig = {
+      DynamicUser = false;
+      StateDirectory = cfg.stateDir;
+      WorkingDirectory = workingDir;
+      ExecStart = ''
+        ${pkgs.python3Packages.py-air-control-exporter}/bin/py-air-control-exporter \
+          --host ${cfg.deviceHostname} \
+          --protocol ${cfg.protocol} \
+          --listen-port ${toString cfg.port} \
+          --listen-address ${cfg.listenAddress}
+      '';
+      Environment = [ "HOME=${workingDir}" ];
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix
index 1f02ae207249..78fe120e4d93 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix
@@ -10,64 +10,55 @@ let
       echo '${builtins.toJSON conf}' | ${pkgs.buildPackages.jq}/bin/jq '.' > $out
     '';
 
-  generateConfig = extraLabels: (map (path: {
-    name = "rspamd_${replaceStrings [ "." " " ] [ "_" "_" ] path}";
-    path = "$.${path}";
-    labels = extraLabels;
-  }) [
-    "actions.'add header'"
-    "actions.'no action'"
-    "actions.'rewrite subject'"
-    "actions.'soft reject'"
-    "actions.greylist"
-    "actions.reject"
-    "bytes_allocated"
-    "chunks_allocated"
-    "chunks_freed"
-    "chunks_oversized"
-    "connections"
-    "control_connections"
-    "ham_count"
-    "learned"
-    "pools_allocated"
-    "pools_freed"
-    "read_only"
-    "scanned"
-    "shared_chunks_allocated"
-    "spam_count"
-    "total_learns"
-  ]) ++ [{
-    name = "rspamd_statfiles";
-    type = "object";
-    path = "$.statfiles[*]";
-    labels = recursiveUpdate {
-      symbol = "$.symbol";
-      type = "$.type";
-    } extraLabels;
-    values = {
-      revision = "$.revision";
-      size = "$.size";
-      total = "$.total";
-      used = "$.used";
-      languages = "$.languages";
-      users = "$.users";
-    };
-  }];
+  generateConfig = extraLabels: {
+    metrics = (map (path: {
+      name = "rspamd_${replaceStrings [ "." " " ] [ "_" "_" ] path}";
+      path = "$.${path}";
+      labels = extraLabels;
+    }) [
+      "actions.'add header'"
+      "actions.'no action'"
+      "actions.'rewrite subject'"
+      "actions.'soft reject'"
+      "actions.greylist"
+      "actions.reject"
+      "bytes_allocated"
+      "chunks_allocated"
+      "chunks_freed"
+      "chunks_oversized"
+      "connections"
+      "control_connections"
+      "ham_count"
+      "learned"
+      "pools_allocated"
+      "pools_freed"
+      "read_only"
+      "scanned"
+      "shared_chunks_allocated"
+      "spam_count"
+      "total_learns"
+    ]) ++ [{
+      name = "rspamd_statfiles";
+      type = "object";
+      path = "$.statfiles[*]";
+      labels = recursiveUpdate {
+        symbol = "$.symbol";
+        type = "$.type";
+      } extraLabels;
+      values = {
+        revision = "$.revision";
+        size = "$.size";
+        total = "$.total";
+        used = "$.used";
+        languages = "$.languages";
+        users = "$.users";
+      };
+    }];
+  };
 in
 {
   port = 7980;
   extraOpts = {
-    listenAddress = {}; # not used
-
-    url = mkOption {
-      type = types.str;
-      description = ''
-        URL to the rspamd metrics endpoint.
-        Defaults to http://localhost:11334/stat when
-        <option>services.rspamd.enable</option> is true.
-      '';
-    };
-
     extraLabels = mkOption {
       type = types.attrsOf types.str;
       default = {
@@ -84,9 +75,25 @@ in
     };
   };
   serviceOpts.serviceConfig.ExecStart = ''
-    ${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \
-      --port ${toString cfg.port} \
-      ${cfg.url} ${prettyJSON (generateConfig cfg.extraLabels)} \
+    ${pkgs.prometheus-json-exporter}/bin/json_exporter \
+      --config.file ${prettyJSON (generateConfig cfg.extraLabels)} \
+      --web.listen-address "${cfg.listenAddress}:${toString cfg.port}" \
       ${concatStringsSep " \\\n  " cfg.extraFlags}
   '';
+
+  imports = [
+    (mkRemovedOptionModule [ "url" ] ''
+      This option was removed. The URL of the rspamd metrics endpoint
+      must now be provided to the exporter by prometheus via the url
+      parameter `target'.
+
+      In prometheus a scrape URL would look like this:
+
+        http://some.rspamd-exporter.host:7980/probe?target=http://some.rspamd.host:11334/stat
+
+      For more information, take a look at the official documentation
+      (https://github.com/prometheus-community/json_exporter) of the json_exporter.
+    '')
+     ({ options.warnings = options.warnings; options.assertions = options.assertions; })
+  ];
 }
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix
new file mode 100644
index 000000000000..01e420db3897
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix
@@ -0,0 +1,78 @@
+{ config, lib, pkgs, options }:
+
+let
+  cfg = config.services.prometheus.exporters.rtl_433;
+in
+{
+  port = 9550;
+
+  extraOpts = let
+    mkMatcherOptionType = field: description: with lib.types;
+      listOf (submodule {
+        options = {
+          name = lib.mkOption {
+            type = str;
+            description = "Name to match.";
+          };
+          "${field}" = lib.mkOption {
+            type = int;
+            inherit description;
+          };
+          location = lib.mkOption {
+            type = str;
+            description = "Location to match.";
+          };
+        };
+      });
+  in
+  {
+    rtl433Flags = lib.mkOption {
+      type = lib.types.str;
+      default = "-C si";
+      example = "-C si -R 19";
+      description = ''
+        Flags passed verbatim to rtl_433 binary.
+        Having <literal>-C si</literal> (the default) is recommended since only Celsius temperatures are parsed.
+      '';
+    };
+    channels = lib.mkOption {
+      type = mkMatcherOptionType "channel" "Channel to match.";
+      default = [];
+      example = [
+        { name = "Acurite"; channel = 6543; location = "Kitchen"; }
+      ];
+      description = ''
+        List of channel matchers to export.
+      '';
+    };
+    ids = lib.mkOption {
+      type = mkMatcherOptionType "id" "ID to match.";
+      default = [];
+      example = [
+        { name = "Nexus"; id = 1; location = "Bedroom"; }
+      ];
+      description = ''
+        List of ID matchers to export.
+      '';
+    };
+  };
+
+  serviceOpts = {
+    serviceConfig = {
+      # rtl-sdr udev rules make supported USB devices +rw by plugdev.
+      SupplementaryGroups = "plugdev";
+      ExecStart = let
+        matchers = (map (m:
+          "--channel_matcher '${m.name},${toString m.channel},${m.location}'"
+        ) cfg.channels) ++ (map (m:
+          "--id_matcher '${m.name},${toString m.id},${m.location}'"
+        ) cfg.ids); in ''
+        ${pkgs.prometheus-rtl_433-exporter}/bin/rtl_433_prometheus \
+          -listen ${cfg.listenAddress}:${toString cfg.port} \
+          -subprocess "${pkgs.rtl_433}/bin/rtl_433 -F json ${cfg.rtl433Flags}" \
+          ${lib.concatStringsSep " \\\n  " matchers} \
+          ${lib.concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smokeping.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smokeping.nix
new file mode 100644
index 000000000000..0a7bb9c27be2
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smokeping.nix
@@ -0,0 +1,60 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.smokeping;
+  goDuration = types.mkOptionType {
+    name = "goDuration";
+    description = "Go duration (https://golang.org/pkg/time/#ParseDuration)";
+    check = x: types.str.check x && builtins.match "(-?[0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+" x != null;
+    inherit (types.str) merge;
+  };
+in
+{
+  port = 9374;
+  extraOpts = {
+    telemetryPath = mkOption {
+      type = types.str;
+      default = "/metrics";
+      description = ''
+        Path under which to expose metrics.
+      '';
+    };
+    pingInterval = mkOption {
+      type = goDuration;
+      default = "1s";
+      description = ''
+        Interval between pings.
+      '';
+    };
+    buckets = mkOption {
+      type = types.commas;
+      default = "5e-05,0.0001,0.0002,0.0004,0.0008,0.0016,0.0032,0.0064,0.0128,0.0256,0.0512,0.1024,0.2048,0.4096,0.8192,1.6384,3.2768,6.5536,13.1072,26.2144";
+      description = ''
+        List of buckets to use for the response duration histogram.
+      '';
+    };
+    hosts = mkOption {
+      type = with types; listOf str;
+      description = ''
+        List of endpoints to probe.
+      '';
+    };
+  };
+  serviceOpts = {
+    serviceConfig = {
+      AmbientCapabilities = [ "CAP_NET_RAW" ];
+      ExecStart = ''
+        ${pkgs.prometheus-smokeping-prober}/bin/smokeping_prober \
+          --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          --web.telemetry-path ${cfg.telemetryPath} \
+          --buckets ${cfg.buckets} \
+          --ping.interval ${cfg.pingInterval} \
+          --privileged \
+          ${concatStringsSep " \\\n  " cfg.extraFlags} \
+          ${concatStringsSep " " cfg.hosts}
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix
new file mode 100644
index 000000000000..d9be724ebc03
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix
@@ -0,0 +1,104 @@
+{ config, lib, pkgs, options }:
+with lib;
+let
+  cfg = config.services.prometheus.exporters.sql;
+  cfgOptions = {
+    options = with types; {
+      jobs = mkOption {
+        type = attrsOf (submodule jobOptions);
+        default = { };
+        description = "An attrset of metrics scraping jobs to run.";
+      };
+    };
+  };
+  jobOptions = {
+    options = with types; {
+      interval = mkOption {
+        type = str;
+        description = ''
+          How often to run this job, specified in
+          <link xlink:href="https://golang.org/pkg/time/#ParseDuration">Go duration</link> format.
+        '';
+      };
+      connections = mkOption {
+        type = listOf str;
+        description = "A list of connection strings of the SQL servers to scrape metrics from";
+      };
+      startupSql = mkOption {
+        type = listOf str;
+        default = [];
+        description = "A list of SQL statements to execute once after making a connection.";
+      };
+      queries = mkOption {
+        type = attrsOf (submodule queryOptions);
+        description = "SQL queries to run.";
+      };
+    };
+  };
+  queryOptions = {
+    options = with types; {
+      help = mkOption {
+        type = nullOr str;
+        default = null;
+        description = "A human-readable description of this metric.";
+      };
+      labels = mkOption {
+        type = listOf str;
+        default = [ ];
+        description = "A set of columns that will be used as Prometheus labels.";
+      };
+      query = mkOption {
+        type = str;
+        description = "The SQL query to run.";
+      };
+      values = mkOption {
+        type = listOf str;
+        description = "A set of columns that will be used as values of this metric.";
+      };
+    };
+  };
+
+  configFile =
+    if cfg.configFile != null
+    then cfg.configFile
+    else
+      let
+        nameInline = mapAttrsToList (k: v: v // { name = k; });
+        renameStartupSql = j: removeAttrs (j // { startup_sql = j.startupSql; }) [ "startupSql" ];
+        configuration = {
+          jobs = map renameStartupSql
+            (nameInline (mapAttrs (k: v: (v // { queries = nameInline v.queries; })) cfg.configuration.jobs));
+        };
+      in
+      builtins.toFile "config.yaml" (builtins.toJSON configuration);
+in
+{
+  extraOpts = {
+    configFile = mkOption {
+      type = with types; nullOr path;
+      default = null;
+      description = ''
+        Path to configuration file.
+      '';
+    };
+    configuration = mkOption {
+      type = with types; nullOr (submodule cfgOptions);
+      default = null;
+      description = ''
+        Exporter configuration as nix attribute set. Mutually exclusive with 'configFile' option.
+      '';
+    };
+  };
+
+  port = 9237;
+  serviceOpts = {
+    serviceConfig = {
+      ExecStart = ''
+        ${pkgs.prometheus-sql-exporter}/bin/sql_exporter \
+          -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          -config.file ${configFile} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/smartd.nix b/nixpkgs/nixos/modules/services/monitoring/smartd.nix
index c72b4abfcdce..3ea254371142 100644
--- a/nixpkgs/nixos/modules/services/monitoring/smartd.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/smartd.nix
@@ -36,7 +36,7 @@ let
 
       $SMARTD_MESSAGE
       EOF
-      } | ${pkgs.utillinux}/bin/wall 2>/dev/null
+      } | ${pkgs.util-linux}/bin/wall 2>/dev/null
     ''}
     ${optionalString nx.enable ''
       export DISPLAY=${nx.display}
diff --git a/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix b/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix
index 8d781d82d086..ce9e57a187cd 100644
--- a/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix
@@ -31,14 +31,14 @@ in
       after = [ "NetworkManager-wait-online.service" "network.target" ];
       preStart = "mkdir -pv /var/lib/teamviewer /var/log/teamviewer";
 
+      startLimitIntervalSec = 60;
+      startLimitBurst = 10;
       serviceConfig = {
         Type = "forking";
         ExecStart = "${pkgs.teamviewer}/bin/teamviewerd -d";
         PIDFile = "/run/teamviewerd.pid";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         Restart = "on-abort";
-        StartLimitInterval = "60";
-        StartLimitBurst = "10";
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/monitoring/telegraf.nix b/nixpkgs/nixos/modules/services/monitoring/telegraf.nix
index 5d131557e8be..b341a9005c2a 100644
--- a/nixpkgs/nixos/modules/services/monitoring/telegraf.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/telegraf.nix
@@ -5,14 +5,8 @@ with lib;
 let
   cfg = config.services.telegraf;
 
-  configFile = pkgs.runCommand "config.toml" {
-    buildInputs = [ pkgs.remarshal ];
-    preferLocalBuild = true;
-  } ''
-    remarshal -if json -of toml \
-      < ${pkgs.writeText "config.json" (builtins.toJSON cfg.extraConfig)} \
-      > $out
-  '';
+  settingsFormat = pkgs.formats.toml {};
+  configFile = settingsFormat.generate "config.toml" cfg.extraConfig;
 in {
   ###### interface
   options = {
@@ -26,22 +20,31 @@ in {
         type = types.package;
       };
 
+      environmentFiles = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        example = "/run/keys/telegraf.env";
+        description = ''
+          File to load as environment file. Environment variables
+          from this file will be interpolated into the config file
+          using envsubst with this syntax:
+          <literal>$ENVIRONMENT ''${VARIABLE}</literal>
+          This is useful to avoid putting secrets into the nix store.
+        '';
+      };
+
       extraConfig = mkOption {
         default = {};
         description = "Extra configuration options for telegraf";
-        type = types.attrs;
+        type = settingsFormat.type;
         example = {
-          outputs = {
-            influxdb = {
-              urls = ["http://localhost:8086"];
-              database = "telegraf";
-            };
+          outputs.influxdb = {
+            urls = ["http://localhost:8086"];
+            database = "telegraf";
           };
-          inputs = {
-            statsd = {
-              service_address = ":8125";
-              delete_timings = true;
-            };
+          inputs.statsd = {
+            service_address = ":8125";
+            delete_timings = true;
           };
         };
       };
@@ -51,15 +54,28 @@ in {
 
   ###### implementation
   config = mkIf config.services.telegraf.enable {
-    systemd.services.telegraf = {
+    systemd.services.telegraf = let
+      finalConfigFile = if config.services.telegraf.environmentFiles == []
+                        then configFile
+                        else "/var/run/telegraf/config.toml";
+    in {
       description = "Telegraf Agent";
       wantedBy = [ "multi-user.target" ];
       after = [ "network-online.target" ];
       serviceConfig = {
-        ExecStart=''${cfg.package}/bin/telegraf -config "${configFile}"'';
+        EnvironmentFile = config.services.telegraf.environmentFiles;
+        ExecStartPre = lib.optional (config.services.telegraf.environmentFiles != [])
+          (pkgs.writeShellScript "pre-start" ''
+            umask 077
+            ${pkgs.envsubst}/bin/envsubst -i "${configFile}" > /var/run/telegraf/config.toml
+          '');
+        ExecStart=''${cfg.package}/bin/telegraf -config ${finalConfigFile}'';
         ExecReload="${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        RuntimeDirectory = "telegraf";
         User = "telegraf";
         Restart = "on-failure";
+        # for ping probes
+        AmbientCapabilities = [ "CAP_NET_RAW" ];
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix b/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix
index d17959a6a305..f2dc740fd88e 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix
@@ -28,6 +28,9 @@ let
 
     # Don't start services that are not yet initialized
     unitConfig.ConditionPathExists = "/var/lib/${stateDirectory}/keyring";
+    startLimitBurst =
+      if daemonType == "osd" then 30 else if lib.elem daemonType ["mgr" "mds"] then 3 else 5;
+    startLimitIntervalSec = 60 * 30;  # 30 mins
 
     serviceConfig = {
       LimitNOFILE = 1048576;
@@ -39,8 +42,6 @@ let
       ProtectHome = "true";
       ProtectSystem = "full";
       Restart = "on-failure";
-      StartLimitBurst = "5";
-      StartLimitInterval = "30min";
       StateDirectory = stateDirectory;
       User = "ceph";
       Group = if daemonType == "osd" then "disk" else "ceph";
@@ -48,13 +49,10 @@ let
                     -f --cluster ${clusterName} --id ${daemonId}'';
     } // optionalAttrs (daemonType == "osd") {
       ExecStartPre = ''${ceph.lib}/libexec/ceph/ceph-osd-prestart.sh --id ${daemonId} --cluster ${clusterName}'';
-      StartLimitBurst = "30";
       RestartSec = "20s";
       PrivateDevices = "no"; # osd needs disk access
     } // optionalAttrs ( daemonType == "mon") {
       RestartSec = "10";
-    } // optionalAttrs (lib.elem daemonType ["mgr" "mds"]) {
-      StartLimitBurst = "3";
     };
   });
 
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix
index f298f831fa7b..2082d513161e 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix
@@ -44,6 +44,13 @@ in {
 
       enable = mkEnableOption "Interplanetary File System (WARNING: may cause severe network degredation)";
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.ipfs;
+        defaultText = "pkgs.ipfs";
+        description = "Which IPFS package to use.";
+      };
+
       user = mkOption {
         type = types.str;
         default = "ipfs";
@@ -176,7 +183,7 @@ in {
   ###### implementation
 
   config = mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.ipfs ];
+    environment.systemPackages = [ cfg.package ];
     environment.variables.IPFS_PATH = cfg.dataDir;
 
     programs.fuse = mkIf cfg.autoMount {
@@ -207,14 +214,14 @@ in {
       "d '${cfg.ipnsMountDir}' - ${cfg.user} ${cfg.group} - -"
     ];
 
-    systemd.packages = [ pkgs.ipfs ];
+    systemd.packages = [ cfg.package ];
 
     systemd.services.ipfs-init = {
       description = "IPFS Initializer";
 
       environment.IPFS_PATH = cfg.dataDir;
 
-      path = [ pkgs.ipfs ];
+      path = [ cfg.package ];
 
       script = ''
         if [[ ! -f ${cfg.dataDir}/config ]]; then
@@ -239,7 +246,7 @@ in {
     };
 
     systemd.services.ipfs = {
-      path = [ "/run/wrappers" pkgs.ipfs ];
+      path = [ "/run/wrappers" cfg.package ];
       environment.IPFS_PATH = cfg.dataDir;
 
       wants = [ "ipfs-init.service" ];
@@ -267,7 +274,7 @@ in {
               cfg.extraConfig))
           );
       serviceConfig = {
-        ExecStart = ["" "${pkgs.ipfs}/bin/ipfs daemon ${ipfsFlags}"];
+        ExecStart = ["" "${cfg.package}/bin/ipfs daemon ${ipfsFlags}"];
         User = cfg.user;
         Group = cfg.group;
       } // optionalAttrs (cfg.serviceFdlimit != null) { LimitNOFILE = cfg.serviceFdlimit; };
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/netatalk.nix b/nixpkgs/nixos/modules/services/network-filesystems/netatalk.nix
index 7674c8f7fa8d..ca9d32311f5f 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/netatalk.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/netatalk.nix
@@ -108,10 +108,10 @@ in
 
       extmap = mkOption {
         type = types.lines;
-	default = "";
-	description = ''
-	  File name extension mappings.
-	  See <literal>man extmap.conf</literal> for more information.
+        default = "";
+        description = ''
+          File name extension mappings.
+          See <literal>man extmap.conf</literal> for more information.
         '';
       };
 
@@ -132,10 +132,10 @@ in
         Type = "forking";
         GuessMainPID = "no";
         PIDFile = "/run/lock/netatalk";
-	ExecStartPre = "${pkgs.coreutils}/bin/mkdir -m 0755 -p /var/lib/netatalk/CNID";
+        ExecStartPre = "${pkgs.coreutils}/bin/mkdir -m 0755 -p /var/lib/netatalk/CNID";
         ExecStart  = "${pkgs.netatalk}/sbin/netatalk -F ${afpConfFile}";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP  $MAINPID";
-	ExecStop   = "${pkgs.coreutils}/bin/kill -TERM $MAINPID";
+        ExecStop   = "${pkgs.coreutils}/bin/kill -TERM $MAINPID";
         Restart = "always";
         RestartSec = 1;
       };
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix b/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix
index 677111814a01..03884cb72976 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix
@@ -244,7 +244,7 @@ in
       # postStop, then we get a hang + kernel oops, because AFS can't be
       # stopped simply by sending signals to processes.
       preStop = ''
-        ${pkgs.utillinux}/bin/umount ${cfg.mountPoint}
+        ${pkgs.util-linux}/bin/umount ${cfg.mountPoint}
         ${openafsBin}/sbin/afsd -shutdown
         ${pkgs.kmod}/sbin/rmmod libafs
       '';
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/openafs/server.nix b/nixpkgs/nixos/modules/services/network-filesystems/openafs/server.nix
index 095024d2c8af..d782f7821656 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/openafs/server.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/openafs/server.nix
@@ -251,7 +251,6 @@ in {
         wantedBy = [ "multi-user.target" ];
         restartIfChanged = false;
         unitConfig.ConditionPathExists = [
-          "|/etc/openafs/server/rxkad.keytab"
           "|/etc/openafs/server/KeyFileExt"
         ];
         preStart = ''
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/rsyncd.nix b/nixpkgs/nixos/modules/services/network-filesystems/rsyncd.nix
index fa29e18a9395..9f1263ddff56 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/rsyncd.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/rsyncd.nix
@@ -3,120 +3,76 @@
 with lib;
 
 let
-
   cfg = config.services.rsyncd;
-
-  motdFile = builtins.toFile "rsyncd-motd" cfg.motd;
-
-  foreach = attrs: f:
-    concatStringsSep "\n" (mapAttrsToList f attrs);
-
-  cfgFile = ''
-    ${optionalString (cfg.motd != "") "motd file = ${motdFile}"}
-    ${optionalString (cfg.address != "") "address = ${cfg.address}"}
-    ${optionalString (cfg.port != 873) "port = ${toString cfg.port}"}
-    ${cfg.extraConfig}
-    ${foreach cfg.modules (name: module: ''
-      [${name}]
-      ${foreach module (k: v:
-        "${k} = ${v}"
-      )}
-    '')}
-  '';
-in
-
-{
+  settingsFormat = pkgs.formats.ini { };
+  configFile = settingsFormat.generate "rsyncd.conf" cfg.settings;
+in {
   options = {
     services.rsyncd = {
 
       enable = mkEnableOption "the rsync daemon";
 
-      motd = mkOption {
-        type = types.str;
-        default = "";
-        description = ''
-          Message of the day to display to clients on each connect.
-          This usually contains site information and any legal notices.
-        '';
-      };
-
       port = mkOption {
         default = 873;
-        type = types.int;
+        type = types.port;
         description = "TCP port the daemon will listen on.";
       };
 
-      address = mkOption {
-        default = "";
-        example = "192.168.1.2";
-        description = ''
-          IP address the daemon will listen on; rsyncd will listen on
-          all addresses if this is not specified.
-        '';
-      };
-
-      extraConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = ''
-            Lines of configuration to add to rsyncd globally.
-            See <command>man rsyncd.conf</command> for options.
-          '';
-      };
-
-      modules = mkOption {
-        default = {};
-        description = ''
-            A set describing exported directories.
-            See <command>man rsyncd.conf</command> for options.
-          '';
-        type = types.attrsOf (types.attrsOf types.str);
-        example = literalExample ''
-          { srv =
-             { path = "/srv";
-               "read only" = "yes";
-               comment = "Public rsync share.";
-             };
-          }
-        '';
-      };
-
-      user = mkOption {
-        type = types.str;
-        default = "root";
-        description = ''
-          The user to run the daemon as.
-          By default the daemon runs as root.
-        '';
-      };
-
-      group = mkOption {
-        type = types.str;
-        default = "root";
+      settings = mkOption {
+        inherit (settingsFormat) type;
+        default = { };
+        example = {
+          global = {
+            uid = "nobody";
+            gid = "nobody";
+            "use chroot" = true;
+            "max connections" = 4;
+          };
+          ftp = {
+            path = "/var/ftp/./pub";
+            comment = "whole ftp area";
+          };
+          cvs = {
+            path = "/data/cvs";
+            comment = "CVS repository (requires authentication)";
+            "auth users" = [ "tridge" "susan" ];
+            "secrets file" = "/etc/rsyncd.secrets";
+          };
+        };
         description = ''
-          The group to run the daemon as.
-          By default the daemon runs as root.
+          Configuration for rsyncd. See
+          <citerefentry><refentrytitle>rsyncd.conf</refentrytitle>
+          <manvolnum>5</manvolnum></citerefentry>.
         '';
       };
 
     };
   };
 
-  ###### implementation
+  imports = (map (option:
+    mkRemovedOptionModule [ "services" "rsyncd" option ]
+    "This option was removed in favor of `services.rsyncd.settings`.") [
+      "address"
+      "extraConfig"
+      "motd"
+      "user"
+      "group"
+    ]);
 
   config = mkIf cfg.enable {
 
-    environment.etc."rsyncd.conf".text = cfgFile;
+    services.rsyncd.settings.global.port = toString cfg.port;
 
     systemd.services.rsyncd = {
       description = "Rsync daemon";
       wantedBy = [ "multi-user.target" ];
-      restartTriggers = [ config.environment.etc."rsyncd.conf".source ];
-      serviceConfig = {
-        ExecStart = "${pkgs.rsync}/bin/rsync --daemon --no-detach";
-        User = cfg.user;
-        Group = cfg.group;
-      };
+      serviceConfig.ExecStart =
+        "${pkgs.rsync}/bin/rsync --daemon --no-detach --config=${configFile}";
     };
   };
+
+  meta.maintainers = with lib.maintainers; [ ehmry ];
+
+  # TODO: socket activated rsyncd
+
 }
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/samba-wsdd.nix b/nixpkgs/nixos/modules/services/network-filesystems/samba-wsdd.nix
new file mode 100644
index 000000000000..c68039c79e2b
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/network-filesystems/samba-wsdd.nix
@@ -0,0 +1,124 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.samba-wsdd;
+
+in {
+  options = {
+    services.samba-wsdd = {
+      enable = mkEnableOption ''
+        Enable Web Services Dynamic Discovery host daemon. This enables (Samba) hosts, like your local NAS device,
+        to be found by Web Service Discovery Clients like Windows.
+        <note>
+          <para>If you use the firewall consider adding the following:</para>
+          <programlisting>
+            networking.firewall.allowedTCPPorts = [ 5357 ];
+            networking.firewall.allowedUDPPorts = [ 3702 ];
+          </programlisting>
+        </note>
+      '';
+      interface = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "eth0";
+        description = "Interface or address to use.";
+      };
+      hoplimit = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 2;
+        description = "Hop limit for multicast packets (default = 1).";
+      };
+      workgroup = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "HOME";
+        description = "Set workgroup name (default WORKGROUP).";
+      };
+      hostname = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        example = "FILESERVER";
+        description = "Override (NetBIOS) hostname to be used (default hostname).";
+      };
+      domain = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "Set domain name (disables workgroup).";
+      };
+      discovery = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Enable discovery operation mode.";
+      };
+      listen = mkOption {
+        type = types.str;
+        default = "/run/wsdd/wsdd.sock";
+        description = "Listen on path or localhost port in discovery mode.";
+      };
+      extraOptions = mkOption {
+        type = types.listOf types.str;
+        default = [ "--shortlog" ];
+        example = [ "--verbose" "--no-http" "--ipv4only" "--no-host" ];
+        description = "Additional wsdd options.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.wsdd ];
+
+    systemd.services.samba-wsdd = {
+      description = "Web Services Dynamic Discovery host daemon";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        DynamicUser = true;
+        Type = "simple";
+        ExecStart = ''
+          ${pkgs.wsdd}/bin/wsdd ${optionalString (cfg.interface != null) "--interface '${cfg.interface}'"} \
+                                ${optionalString (cfg.hoplimit != null) "--hoplimit '${toString cfg.hoplimit}'"} \
+                                ${optionalString (cfg.workgroup != null) "--workgroup '${cfg.workgroup}'"} \
+                                ${optionalString (cfg.hostname != null) "--hostname '${cfg.hostname}'"} \
+                                ${optionalString (cfg.domain != null) "--domain '${cfg.domain}'"} \
+                                ${optionalString cfg.discovery "--discovery --listen '${cfg.listen}'"} \
+                                ${escapeShellArgs cfg.extraOptions}
+        '';
+        # Runtime directory and mode
+        RuntimeDirectory = "wsdd";
+        RuntimeDirectoryMode = "0750";
+        # Access write directories
+        UMask = "0027";
+        # Capabilities
+        CapabilityBoundingSet = "";
+        # Security
+        NoNewPrivileges = true;
+        # Sandboxing
+        ProtectSystem = "strict";
+        ProtectHome = true;
+        PrivateTmp = true;
+        PrivateDevices = true;
+        PrivateUsers = false;
+        ProtectHostname = true;
+        ProtectClock = true;
+        ProtectKernelTunables = true;
+        ProtectKernelModules = true;
+        ProtectKernelLogs = true;
+        ProtectControlGroups = true;
+        RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ];
+        RestrictNamespaces = true;
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        PrivateMounts = true;
+        # System Call Filtering
+        SystemCallArchitectures = "native";
+        SystemCallFilter = "~@clock @cpu-emulation @debug @module @mount @obsolete @privileged @raw-io @reboot @resources @swap";
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/samba.nix b/nixpkgs/nixos/modules/services/network-filesystems/samba.nix
index 7d3c601d6cd5..d6e2904b3c36 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/samba.nix
@@ -26,7 +26,6 @@ let
       [global]
       security = ${cfg.securityType}
       passwd program = /run/wrappers/bin/passwd %u
-      pam password change = ${smbToString cfg.syncPasswordsByPam}
       invalid users = ${smbToString cfg.invalidUsers}
 
       ${cfg.extraConfig}
@@ -67,6 +66,7 @@ in
 {
   imports = [
     (mkRemovedOptionModule [ "services" "samba" "defaultShare" ] "")
+    (mkRemovedOptionModule [ "services" "samba" "syncPasswordsByPam" ] "This option has been removed by upstream, see https://bugzilla.samba.org/show_bug.cgi?id=10669#c10")
   ];
 
   ###### interface
@@ -124,18 +124,6 @@ in
         '';
       };
 
-      syncPasswordsByPam = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Enabling this will add a line directly after pam_unix.so.
-          Whenever a password is changed the samba password will be updated as well.
-          However, you still have to add the samba password once, using smbpasswd -a user.
-          If you don't want to maintain an extra password database, you still can send plain text
-          passwords which is not secure.
-        '';
-      };
-
       invalidUsers = mkOption {
         type = types.listOf types.str;
         default = [ "root" ];
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/xtreemfs.nix b/nixpkgs/nixos/modules/services/network-filesystems/xtreemfs.nix
index b8f8c1d71174..27a9fe847c58 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/xtreemfs.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/xtreemfs.nix
@@ -112,7 +112,7 @@ in
           description = ''
             Must be set to a unique identifier, preferably a UUID according to
             RFC 4122. UUIDs can be generated with `uuidgen` command, found in
-            the `utillinux` package.
+            the `util-linux` package.
           '';
         };
         port = mkOption {
@@ -232,7 +232,7 @@ in
           description = ''
             Must be set to a unique identifier, preferably a UUID according to
             RFC 4122. UUIDs can be generated with `uuidgen` command, found in
-            the `utillinux` package.
+            the `util-linux` package.
           '';
         };
         port = mkOption {
@@ -370,7 +370,7 @@ in
           description = ''
             Must be set to a unique identifier, preferably a UUID according to
             RFC 4122. UUIDs can be generated with `uuidgen` command, found in
-            the `utillinux` package.
+            the `util-linux` package.
           '';
         };
         port = mkOption {
diff --git a/nixpkgs/nixos/modules/services/networking/avahi-daemon.nix b/nixpkgs/nixos/modules/services/networking/avahi-daemon.nix
index c876b252e8cd..0b7d5575c11f 100644
--- a/nixpkgs/nixos/modules/services/networking/avahi-daemon.nix
+++ b/nixpkgs/nixos/modules/services/networking/avahi-daemon.nix
@@ -86,7 +86,8 @@ in
 
     ipv6 = mkOption {
       type = types.bool;
-      default = false;
+      default = config.networking.enableIPv6;
+      defaultText = "config.networking.enableIPv6";
       description = "Whether to use IPv6.";
     };
 
@@ -239,7 +240,7 @@ in
 
     system.nssModules = optional cfg.nssmdns pkgs.nssmdns;
     system.nssDatabases.hosts = optionals cfg.nssmdns (mkMerge [
-      [ "mdns_minimal [NOTFOUND=return]" ]
+      (mkOrder 900 [ "mdns_minimal [NOTFOUND=return]" ]) # must be before resolve
       (mkOrder 1501 [ "mdns" ]) # 1501 to ensure it's after dns
     ]);
 
diff --git a/nixpkgs/nixos/modules/services/networking/babeld.nix b/nixpkgs/nixos/modules/services/networking/babeld.nix
index e62c74d0069d..90395dbd3c54 100644
--- a/nixpkgs/nixos/modules/services/networking/babeld.nix
+++ b/nixpkgs/nixos/modules/services/networking/babeld.nix
@@ -87,9 +87,37 @@ in
       description = "Babel routing daemon";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      serviceConfig.ExecStart = "${pkgs.babeld}/bin/babeld -c ${configFile}";
+      serviceConfig = {
+        ExecStart = "${pkgs.babeld}/bin/babeld -c ${configFile} -I /run/babeld/babeld.pid -S /var/lib/babeld/state";
+        CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
+        IPAddressAllow = [ "fe80::/64" "ff00::/8" "::1/128" "127.0.0.0/8" ];
+        IPAddressDeny = "any";
+        LockPersonality = true;
+        NoNewPrivileges = true;
+        MemoryDenyWriteExecute = true;
+        ProtectSystem = "strict";
+        ProtectClock = true;
+        ProtectKernelTunables = false; # Couldn't write sysctl: Read-only file system
+        ProtectKernelModules = true;
+        ProtectKernelLogs = true;
+        ProtectControlGroups = true;
+        RestrictAddressFamilies = [ "AF_NETLINK" "AF_INET6" ];
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        RemoveIPC = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        PrivateMounts = true;
+        PrivateTmp = true;
+        PrivateDevices = true;
+        PrivateUsers = false; # kernel_route(ADD): Operation not permitted
+        SystemCallArchitectures = "native";
+        SystemCallFilter = [ "@system-service" ];
+        UMask = "0177";
+        RuntimeDirectory = "babeld";
+        StateDirectory = "babeld";
+      };
     };
-
   };
-
 }
diff --git a/nixpkgs/nixos/modules/services/networking/blockbook-frontend.nix b/nixpkgs/nixos/modules/services/networking/blockbook-frontend.nix
index dde24522756a..ca323e495ec1 100644
--- a/nixpkgs/nixos/modules/services/networking/blockbook-frontend.nix
+++ b/nixpkgs/nixos/modules/services/networking/blockbook-frontend.nix
@@ -158,15 +158,21 @@ let
         type = types.attrs;
         default = {};
         example = literalExample '' {
-          alternative_estimate_fee = "whatthefee-disabled";
-          alternative_estimate_fee_params = "{\"url\": \"https://whatthefee.io/data.json\", \"periodSeconds\": 60}";
-          fiat_rates = "coingecko";
-          fiat_rates_params = "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"bitcoin\", \"periodSeconds\": 60}";
-          coin_shortcut = "BTC";
-          coin_label = "Bitcoin";
-          xpub_magic = 76067358;
-          xpub_magic_segwit_p2sh = 77429938;
-          xpub_magic_segwit_native = 78792518;
+          "alternative_estimate_fee" = "whatthefee-disabled";
+          "alternative_estimate_fee_params" = "{\"url\": \"https://whatthefee.io/data.json\", \"periodSeconds\": 60}";
+          "fiat_rates" = "coingecko";
+          "fiat_rates_params" = "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"bitcoin\", \"periodSeconds\": 60}";
+          "coin_shortcut" = "BTC";
+          "coin_label" = "Bitcoin";
+          "parse" = true;
+          "subversion" = "";
+          "address_format" = "";
+          "xpub_magic" = 76067358;
+          "xpub_magic_segwit_p2sh" = 77429938;
+          "xpub_magic_segwit_native" = 78792518;
+          "mempool_workers" = 8;
+          "mempool_sub_workers" = 2;
+          "block_addresses_to_keep" = 300;
         }'';
         description = ''
           Additional configurations to be appended to <filename>coin.conf</filename>.
diff --git a/nixpkgs/nixos/modules/services/networking/cjdns.nix b/nixpkgs/nixos/modules/services/networking/cjdns.nix
index 5f8ac96b2292..f116d6392ea7 100644
--- a/nixpkgs/nixos/modules/services/networking/cjdns.nix
+++ b/nixpkgs/nixos/modules/services/networking/cjdns.nix
@@ -264,10 +264,10 @@ in
          ''
       );
 
+      startLimitIntervalSec = 0;
       serviceConfig = {
         Type = "forking";
         Restart = "always";
-        StartLimitInterval = 0;
         RestartSec = 1;
         CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW CAP_SETUID";
         ProtectSystem = true;
diff --git a/nixpkgs/nixos/modules/services/networking/corerad.nix b/nixpkgs/nixos/modules/services/networking/corerad.nix
index d90a5923bc62..4acdd1d69cc4 100644
--- a/nixpkgs/nixos/modules/services/networking/corerad.nix
+++ b/nixpkgs/nixos/modules/services/networking/corerad.nix
@@ -4,13 +4,7 @@ with lib;
 
 let
   cfg = config.services.corerad;
-
-  writeTOML = name: x:
-    pkgs.runCommandNoCCLocal name {
-      passAsFile = ["config"];
-      config = builtins.toJSON x;
-      buildInputs = [ pkgs.go-toml ];
-    } "jsontoml < $configPath > $out";
+  settingsFormat = pkgs.formats.toml {};
 
 in {
   meta.maintainers = with maintainers; [ mdlayher ];
@@ -19,7 +13,7 @@ in {
     enable = mkEnableOption "CoreRAD IPv6 NDP RA daemon";
 
     settings = mkOption {
-      type = types.uniq types.attrs;
+      type = settingsFormat.type;
       example = literalExample ''
         {
           interfaces = [
@@ -64,7 +58,7 @@ in {
 
   config = mkIf cfg.enable {
     # Prefer the config file over settings if both are set.
-    services.corerad.configFile = mkDefault (writeTOML "corerad.toml" cfg.settings);
+    services.corerad.configFile = mkDefault (settingsFormat.generate "corerad.toml" cfg.settings);
 
     systemd.services.corerad = {
       description = "CoreRAD IPv6 NDP RA daemon";
diff --git a/nixpkgs/nixos/modules/services/networking/dhcpcd.nix b/nixpkgs/nixos/modules/services/networking/dhcpcd.nix
index 0507b739d499..d10bffd91474 100644
--- a/nixpkgs/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixpkgs/nixos/modules/services/networking/dhcpcd.nix
@@ -69,6 +69,11 @@ let
         if-carrier-up = "";
       }.${cfg.wait}}
 
+      ${optionalString (config.networking.enableIPv6 == false) ''
+        # Don't solicit or accept IPv6 Router Advertisements and DHCPv6 if disabled IPv6
+        noipv6
+      ''}
+
       ${cfg.extraConfig}
     '';
 
diff --git a/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy2.nix b/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy2.nix
index 28691e838277..ff8a2ab30774 100644
--- a/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy2.nix
+++ b/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy2.nix
@@ -11,7 +11,7 @@ in
     settings = mkOption {
       description = ''
         Attrset that is converted and passed as TOML config file.
-        For available params, see: <link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>
+        For available params, see: <link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/${pkgs.dnscrypt-proxy2.version}/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>
       '';
       example = literalExample ''
         {
@@ -27,6 +27,16 @@ in
       default = {};
     };
 
+    upstreamDefaults = mkOption {
+      description = ''
+        Whether to base the config declared in <literal>services.dnscrypt-proxy2.settings</literal> on the upstream example config (<link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>)
+
+        Disable this if you want to declare your dnscrypt config from scratch.
+      '';
+      type = types.bool;
+      default = true;
+    };
+
     configFile = mkOption {
       description = ''
         Path to TOML config file. See: <link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>
@@ -38,7 +48,13 @@ in
         json = builtins.toJSON cfg.settings;
         passAsFile = [ "json" ];
       } ''
-        ${pkgs.remarshal}/bin/json2toml < $jsonPath > $out
+        ${if cfg.upstreamDefaults then ''
+          ${pkgs.remarshal}/bin/toml2json ${pkgs.dnscrypt-proxy2.src}/dnscrypt-proxy/example-dnscrypt-proxy.toml > example.json
+          ${pkgs.jq}/bin/jq --slurp add example.json $jsonPath > config.json # merges the two
+        '' else ''
+          cp $jsonPath config.json
+        ''}
+        ${pkgs.remarshal}/bin/json2toml < config.json > $out
       '';
       defaultText = literalExample "TOML file generated from services.dnscrypt-proxy2.settings";
     };
@@ -49,13 +65,51 @@ in
     networking.nameservers = lib.mkDefault [ "127.0.0.1" ];
 
     systemd.services.dnscrypt-proxy2 = {
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
+      description = "DNSCrypt-proxy client";
+      wants = [
+        "network-online.target"
+        "nss-lookup.target"
+      ];
+      before = [
+        "nss-lookup.target"
+      ];
+      wantedBy = [
+        "multi-user.target"
+      ];
       serviceConfig = {
         AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+        CacheDirectory = "dnscrypt-proxy";
         DynamicUser = true;
         ExecStart = "${pkgs.dnscrypt-proxy2}/bin/dnscrypt-proxy -config ${cfg.configFile}";
+        LockPersonality = true;
+        LogsDirectory = "dnscrypt-proxy";
+        MemoryDenyWriteExecute = true;
+        NoNewPrivileges = true;
+        NonBlocking = true;
+        PrivateDevices = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectSystem = "strict";
         Restart = "always";
+        RestrictAddressFamilies = [
+          "AF_INET"
+          "AF_INET6"
+        ];
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RuntimeDirectory = "dnscrypt-proxy";
+        StateDirectory = "dnscrypt-proxy";
+        SystemCallArchitectures = "native";
+        SystemCallFilter = [
+          "@system-service"
+          "@chown"
+          "~@resources"
+          "@privileged"
+        ];
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix b/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix
index b9333cd19a2a..ee7e9b0454de 100644
--- a/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix
+++ b/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix
@@ -55,7 +55,10 @@ let
   rotateKeys = ''
     # check if keys are not expired
     keyValid() {
-      fingerprint=$(dnscrypt-wrapper --show-provider-publickey | awk '{print $(NF)}')
+      fingerprint=$(dnscrypt-wrapper \
+        --show-provider-publickey \
+        --provider-publickey-file=${publicKey} \
+        | awk '{print $(NF)}')
       dnscrypt-proxy --test=${toString (cfg.keys.checkInterval + 1)} \
         --resolver-address=127.0.0.1:${toString cfg.port} \
         --provider-name=${cfg.providerName} \
diff --git a/nixpkgs/nixos/modules/services/networking/dnsdist.nix b/nixpkgs/nixos/modules/services/networking/dnsdist.nix
index 8249da69bc1a..05c2bdef83e7 100644
--- a/nixpkgs/nixos/modules/services/networking/dnsdist.nix
+++ b/nixpkgs/nixos/modules/services/networking/dnsdist.nix
@@ -7,7 +7,7 @@ let
   configFile = pkgs.writeText "dndist.conf" ''
     setLocal('${cfg.listenAddress}:${toString cfg.listenPort}')
     ${cfg.extraConfig}
-    '';
+  '';
 in {
   options = {
     services.dnsdist = {
@@ -35,25 +35,19 @@ in {
     };
   };
 
-  config = mkIf config.services.dnsdist.enable {
+  config = mkIf cfg.enable {
+    systemd.packages = [ pkgs.dnsdist ];
+
     systemd.services.dnsdist = {
-      description = "dnsdist load balancer";
       wantedBy = [ "multi-user.target" ];
-      after = ["network.target"];
 
+      startLimitIntervalSec = 0;
       serviceConfig = {
-        Restart="on-failure";
-        RestartSec="1";
         DynamicUser = true;
-        StartLimitInterval="0";
-        PrivateDevices=true;
-        AmbientCapabilities="CAP_NET_BIND_SERVICE";
-        CapabilityBoundingSet="CAP_NET_BIND_SERVICE";
-        ExecStart = "${pkgs.dnsdist}/bin/dnsdist --supervised --disable-syslog --config ${configFile}";
-        ProtectHome=true;
-        RestrictAddressFamilies="AF_UNIX AF_INET AF_INET6";
-        LimitNOFILE="16384";
-        TasksMax="8192";
+
+        # upstream overrides for better nixos compatibility
+        ExecStartPre = [ "" "${pkgs.dnsdist}/bin/dnsdist --check-config --config ${configFile}" ];
+        ExecStart = [ "" "${pkgs.dnsdist}/bin/dnsdist --supervised --disable-syslog --config ${configFile}" ];
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/networking/icecream/daemon.nix b/nixpkgs/nixos/modules/services/networking/icecream/daemon.nix
new file mode 100644
index 000000000000..2975696f9c24
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/icecream/daemon.nix
@@ -0,0 +1,155 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.icecream.daemon;
+in {
+
+  ###### interface
+
+  options = {
+
+    services.icecream.daemon = {
+
+     enable = mkEnableOption "Icecream Daemon";
+
+      openFirewall = mkOption {
+        type = types.bool;
+        description = ''
+          Whether to automatically open receive port in the firewall.
+        '';
+      };
+
+      openBroadcast = mkOption {
+        type = types.bool;
+        description = ''
+          Whether to automatically open the firewall for scheduler discovery.
+        '';
+      };
+
+      cacheLimit = mkOption {
+        type = types.ints.u16;
+        default = 256;
+        description = ''
+          Maximum size in Megabytes of cache used to store compile environments of compile clients.
+        '';
+      };
+
+      netName = mkOption {
+        type = types.str;
+        default = "ICECREAM";
+        description = ''
+          Network name to connect to. A scheduler with the same name needs to be running.
+        '';
+      };
+
+      noRemote = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Prevent jobs from other nodes being scheduled on this daemon.
+        '';
+      };
+
+      schedulerHost = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Explicit scheduler hostname, useful in firewalled environments.
+
+          Uses scheduler autodiscovery via broadcast if set to null.
+        '';
+      };
+
+      maxProcesses = mkOption {
+        type = types.nullOr types.ints.u16;
+        default = null;
+        description = ''
+          Maximum number of compile jobs started in parallel for this daemon.
+
+          Uses the number of CPUs if set to null.
+        '';
+      };
+
+      nice = mkOption {
+        type = types.int;
+        default = 5;
+        description = ''
+          The level of niceness to use.
+        '';
+      };
+
+      hostname = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Hostname of the daemon in the icecream infrastructure.
+
+          Uses the hostname retrieved via uname if set to null.
+        '';
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "icecc";
+        description = ''
+          User to run the icecream daemon as. Set to root to enable receive of
+          remote compile environments.
+        '';
+      };
+
+      package = mkOption {
+        default = pkgs.icecream;
+        defaultText = "pkgs.icecream";
+        type = types.package;
+        description = "Icecream package to use.";
+      };
+
+      extraArgs = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = "Additional command line parameters.";
+        example = [ "-v" ];
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ 10245 ];
+    networking.firewall.allowedUDPPorts = mkIf cfg.openBroadcast [ 8765 ];
+
+    systemd.services.icecc-daemon = {
+      description = "Icecream compile daemon";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = {
+        ExecStart = escapeShellArgs ([
+          "${getBin cfg.package}/bin/iceccd"
+          "-b" "$STATE_DIRECTORY"
+          "-u" "icecc"
+          (toString cfg.nice)
+        ]
+        ++ optionals (cfg.schedulerHost != null) ["-s" cfg.schedulerHost]
+        ++ optionals (cfg.netName != null) [ "-n" cfg.netName ]
+        ++ optionals (cfg.cacheLimit != null) [ "--cache-limit" (toString cfg.cacheLimit) ]
+        ++ optionals (cfg.maxProcesses != null) [ "-m" (toString cfg.maxProcesses) ]
+        ++ optionals (cfg.hostname != null) [ "-N" (cfg.hostname) ]
+        ++ optional  cfg.noRemote "--no-remote"
+        ++ cfg.extraArgs);
+        DynamicUser = true;
+        User = "icecc";
+        Group = "icecc";
+        StateDirectory = "icecc";
+        RuntimeDirectory = "icecc";
+        AmbientCapabilities = "CAP_SYS_CHROOT";
+        CapabilityBoundingSet = "CAP_SYS_CHROOT";
+      };
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ emantor ];
+}
diff --git a/nixpkgs/nixos/modules/services/networking/icecream/scheduler.nix b/nixpkgs/nixos/modules/services/networking/icecream/scheduler.nix
new file mode 100644
index 000000000000..4ccbf27015d7
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/icecream/scheduler.nix
@@ -0,0 +1,101 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.icecream.scheduler;
+in {
+
+  ###### interface
+
+  options = {
+
+    services.icecream.scheduler = {
+      enable = mkEnableOption "Icecream Scheduler";
+
+      netName = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Network name for the icecream scheduler.
+
+          Uses the default ICECREAM if null.
+        '';
+      };
+
+      port = mkOption {
+        type = types.port;
+        default = 8765;
+        description = ''
+          Server port to listen for icecream daemon requests.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        description = ''
+          Whether to automatically open the daemon port in the firewall.
+        '';
+      };
+
+      openTelnet = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to open the telnet TCP port on 8766.
+        '';
+      };
+
+      persistentClientConnection = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to prevent clients from connecting to a better scheduler.
+        '';
+      };
+
+      package = mkOption {
+        default = pkgs.icecream;
+        defaultText = "pkgs.icecream";
+        type = types.package;
+        description = "Icecream package to use.";
+      };
+
+      extraArgs = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = "Additional command line parameters";
+        example = [ "-v" ];
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = mkMerge [
+      (mkIf cfg.openFirewall [ cfg.port ])
+      (mkIf cfg.openTelnet [ 8766 ])
+    ];
+
+    systemd.services.icecc-scheduler = {
+      description = "Icecream scheduling server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = {
+        ExecStart = escapeShellArgs ([
+          "${getBin cfg.package}/bin/icecc-scheduler"
+          "-p" (toString cfg.port)
+        ]
+        ++ optionals (cfg.netName != null) [ "-n" (toString cfg.netName) ]
+        ++ optional cfg.persistentClientConnection "-r"
+        ++ cfg.extraArgs);
+
+        DynamicUser = true;
+      };
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ emantor ];
+}
diff --git a/nixpkgs/nixos/modules/services/networking/kresd.nix b/nixpkgs/nixos/modules/services/networking/kresd.nix
index ccb34163d5f3..074830fc3521 100644
--- a/nixpkgs/nixos/modules/services/networking/kresd.nix
+++ b/nixpkgs/nixos/modules/services/networking/kresd.nix
@@ -23,18 +23,14 @@ let
       '';
 
   configFile = pkgs.writeText "kresd.conf" (
-    optionalString (cfg.listenDoH != []) ''
-      modules.load('http')
-    ''
+    ""
     + concatMapStrings (mkListen "dns") cfg.listenPlain
     + concatMapStrings (mkListen "tls") cfg.listenTLS
-    + concatMapStrings (mkListen "doh") cfg.listenDoH
+    + concatMapStrings (mkListen "doh2") cfg.listenDoH
     + cfg.extraConfig
   );
 
-  package = if cfg.listenDoH == []
-    then pkgs.knot-resolver # never force `extraFeatures = false`
-    else pkgs.knot-resolver.override { extraFeatures = true; };
+  package = pkgs.knot-resolver;
 in {
   meta.maintainers = [ maintainers.vcunat /* upstream developer */ ];
 
@@ -92,7 +88,7 @@ in {
       default = [];
       example = [ "198.51.100.1:443" "[2001:db8::1]:443" "443" ];
       description = ''
-        Addresses and ports on which kresd should provide DNS over HTTPS (see RFC 8484).
+        Addresses and ports on which kresd should provide DNS over HTTPS/2 (see RFC 8484).
         For detailed syntax see ListenStream in man systemd.socket.
       '';
     };
@@ -139,6 +135,8 @@ in {
       CacheDirectory = "knot-resolver";
       CacheDirectoryMode = "0770";
     };
+    # We don't mind running stop phase from wrong version.  It seems less racy.
+    systemd.services."kresd@".stopIfChanged = false;
 
     # Try cleaning up the previously default location of cache file.
     # Note that /var/cache/* should always be safe to remove.
diff --git a/nixpkgs/nixos/modules/services/networking/morty.nix b/nixpkgs/nixos/modules/services/networking/morty.nix
index e3a6444c1163..e110a5c86101 100644
--- a/nixpkgs/nixos/modules/services/networking/morty.nix
+++ b/nixpkgs/nixos/modules/services/networking/morty.nix
@@ -29,9 +29,11 @@ in
       key = mkOption {
         type = types.str;
         default = "";
-        description = "HMAC url validation key (hexadecimal encoded).
-	Leave blank to disable. Without validation key, anyone can
-	submit proxy requests. Leave blank to disable.";
+        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";
       };
 
@@ -85,10 +87,10 @@ in
         serviceConfig = {
           User = "morty";
           ExecStart = ''${cfg.package}/bin/morty              \
-	    -listen ${cfg.listenAddress}:${toString cfg.port} \
-	    ${optionalString cfg.ipv6 "-ipv6"}                \
-	    ${optionalString (cfg.key != "") "-key " + cfg.key} \
-	  '';
+            -listen ${cfg.listenAddress}:${toString cfg.port} \
+            ${optionalString cfg.ipv6 "-ipv6"}                \
+            ${optionalString (cfg.key != "") "-key " + cfg.key} \
+          '';
         };
       };
     environment.systemPackages = [ cfg.package ];
diff --git a/nixpkgs/nixos/modules/services/networking/mosquitto.nix b/nixpkgs/nixos/modules/services/networking/mosquitto.nix
index d2feb93e2b72..10b49d9b2206 100644
--- a/nixpkgs/nixos/modules/services/networking/mosquitto.nix
+++ b/nixpkgs/nixos/modules/services/networking/mosquitto.nix
@@ -123,12 +123,33 @@ in
               '';
             };
 
+            passwordFile = mkOption {
+              type = with types; uniq (nullOr str);
+              example = "/path/to/file";
+              default = null;
+              description = ''
+                Specifies the path to a file containing the
+                clear text password for the MQTT user.
+              '';
+            };
+
             hashedPassword = mkOption {
               type = with types; uniq (nullOr str);
               default = null;
               description = ''
                 Specifies the hashed password for the MQTT User.
-                <option>hashedPassword</option> overrides <option>password</option>.
+                To generate hashed password install <literal>mosquitto</literal>
+                package and use <literal>mosquitto_passwd</literal>.
+              '';
+            };
+
+            hashedPasswordFile = mkOption {
+              type = with types; uniq (nullOr str);
+              example = "/path/to/file";
+              default = null;
+              description = ''
+                Specifies the path to a file containing the
+                hashed password for the MQTT user.
                 To generate hashed password install <literal>mosquitto</literal>
                 package and use <literal>mosquitto_passwd</literal>.
               '';
@@ -190,6 +211,13 @@ in
 
   config = mkIf cfg.enable {
 
+    assertions = mapAttrsToList (name: cfg: {
+      assertion = length (filter (s: s != null) (with cfg; [
+        password passwordFile hashedPassword hashedPasswordFile
+      ])) <= 1;
+      message = "Cannot set more than one password option";
+    }) cfg.users;
+
     systemd.services.mosquitto = {
       description = "Mosquitto MQTT Broker Daemon";
       wantedBy = [ "multi-user.target" ];
@@ -204,13 +232,27 @@ in
         Restart = "on-failure";
         ExecStart = "${pkgs.mosquitto}/bin/mosquitto -c ${mosquittoConf}";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+
+        ProtectSystem = "strict";
+        ProtectHome = true;
+        PrivateDevices = true;
+        PrivateTmp = true;
+        ReadWritePaths = "${cfg.dataDir}";
+        ProtectControlGroups = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        NoNewPrivileges = true;
       };
       preStart = ''
         rm -f ${cfg.dataDir}/passwd
         touch ${cfg.dataDir}/passwd
       '' + concatStringsSep "\n" (
         mapAttrsToList (n: c:
-          if c.hashedPassword != null then
+          if c.hashedPasswordFile != null then
+            "echo '${n}:'$(cat '${c.hashedPasswordFile}') >> ${cfg.dataDir}/passwd"
+          else if c.passwordFile != null then
+            "${pkgs.mosquitto}/bin/mosquitto_passwd -b ${cfg.dataDir}/passwd ${n} $(cat '${c.passwordFile}')"
+          else if c.hashedPassword != null then
             "echo '${n}:${c.hashedPassword}' >> ${cfg.dataDir}/passwd"
           else optionalString (c.password != null)
             "${pkgs.mosquitto}/bin/mosquitto_passwd -b ${cfg.dataDir}/passwd ${n} '${c.password}'"
diff --git a/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix b/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix
index cc98414257ca..6f595ca4be2b 100644
--- a/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix
+++ b/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix
@@ -15,6 +15,9 @@ with lib;
   config = mkIf cfg.enable {
     boot.kernelModules = [ "tun" ];
 
+    # mullvad-daemon writes to /etc/iproute2/rt_tables
+    networking.iproute2.enable = true;
+
     systemd.services.mullvad-daemon = {
       description = "Mullvad VPN daemon";
       wantedBy = [ "multi-user.target" ];
@@ -29,9 +32,9 @@ with lib;
         # Needed for ping
         "/run/wrappers"
       ];
+      startLimitBurst = 5;
+      startLimitIntervalSec = 20;
       serviceConfig = {
-        StartLimitBurst = 5;
-        StartLimitIntervalSec = 20;
         ExecStart = "${pkgs.mullvad-vpn}/bin/mullvad-daemon -v --disable-stdout-timestamps";
         Restart = "always";
         RestartSec = 1;
diff --git a/nixpkgs/nixos/modules/services/networking/murmur.nix b/nixpkgs/nixos/modules/services/networking/murmur.nix
index 3054ae1b201f..c6e5649ec479 100644
--- a/nixpkgs/nixos/modules/services/networking/murmur.nix
+++ b/nixpkgs/nixos/modules/services/networking/murmur.nix
@@ -241,6 +241,34 @@ in
         default = "";
         description = "Extra configuration to put into murmur.ini.";
       };
+
+      environmentFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/var/lib/murmur/murmurd.env";
+        description = ''
+          Environment file as defined in <citerefentry>
+          <refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum>
+          </citerefentry>.
+
+          Secrets may be passed to the service without adding them to the world-readable
+          Nix store, by specifying placeholder variables as the option value in Nix and
+          setting these variables accordingly in the environment file.
+
+          <programlisting>
+            # snippet of murmur-related config
+            services.murmur.password = "$MURMURD_PASSWORD";
+          </programlisting>
+
+          <programlisting>
+            # content of the environment file
+            MURMURD_PASSWORD=verysecretpassword
+          </programlisting>
+
+          Note that this file needs to be available on the host on which
+          <literal>murmur</literal> is running.
+        '';
+      };
     };
   };
 
@@ -250,20 +278,33 @@ in
       home            = "/var/lib/murmur";
       createHome      = true;
       uid             = config.ids.uids.murmur;
+      group           = "murmur";
+    };
+    users.groups.murmur = {
+      gid             = config.ids.gids.murmur;
     };
 
     systemd.services.murmur = {
       description = "Murmur Chat Service";
       wantedBy    = [ "multi-user.target" ];
       after       = [ "network-online.target "];
+      preStart    = ''
+        ${pkgs.envsubst}/bin/envsubst \
+          -o /run/murmur/murmurd.ini \
+          -i ${configFile}
+      '';
 
       serviceConfig = {
         # murmurd doesn't fork when logging to the console.
-        Type      = if forking then "forking" else "simple";
-        PIDFile   = mkIf forking "/run/murmur/murmurd.pid";
-        RuntimeDirectory = mkIf forking "murmur";
-        User      = "murmur";
-        ExecStart = "${pkgs.murmur}/bin/murmurd -ini ${configFile}";
+        Type = if forking then "forking" else "simple";
+        PIDFile = mkIf forking "/run/murmur/murmurd.pid";
+        EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
+        ExecStart = "${pkgs.murmur}/bin/murmurd -ini /run/murmur/murmurd.ini";
+        Restart = "always";
+        RuntimeDirectory = "murmur";
+        RuntimeDirectoryMode = "0700";
+        User = "murmur";
+        Group = "murmur";
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/networking/namecoind.nix b/nixpkgs/nixos/modules/services/networking/namecoind.nix
index 16f85df2e77c..4966ed2cac8d 100644
--- a/nixpkgs/nixos/modules/services/networking/namecoind.nix
+++ b/nixpkgs/nixos/modules/services/networking/namecoind.nix
@@ -165,6 +165,8 @@ in
       after    = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
 
+      startLimitIntervalSec = 120;
+      startLimitBurst = 5;
       serviceConfig = {
         User  = "namecoin";
         Group = "namecoin";
@@ -176,8 +178,6 @@ in
         TimeoutStopSec     = "60s";
         TimeoutStartSec    = "2s";
         Restart            = "always";
-        StartLimitInterval = "120s";
-        StartLimitBurst    = "5";
       };
 
       preStart = optionalString (cfg.wallet != "${dataDir}/wallet.dat")  ''
diff --git a/nixpkgs/nixos/modules/services/networking/nar-serve.nix b/nixpkgs/nixos/modules/services/networking/nar-serve.nix
new file mode 100644
index 000000000000..ddd42fa01073
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/nar-serve.nix
@@ -0,0 +1,55 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+let
+  cfg = config.services.nar-serve;
+in
+{
+  meta = {
+    maintainers = [ maintainers.rizary ];
+  };
+  options = {
+    services.nar-serve = {
+      enable = mkEnableOption "Serve NAR file contents via HTTP";
+
+      port = mkOption {
+        type = types.int;
+        default = 8383;
+        description = ''
+          Port number where nar-serve will listen on.
+        '';
+      };
+
+      cacheURL = mkOption {
+        type = types.str;
+        default = "https://cache.nixos.org/";
+        description = ''
+          Binary cache URL to connect to.
+
+          The URL format is compatible with the nix remote url style, such as:
+          - http://, https:// for binary caches via HTTP or HTTPS
+          - s3:// for binary caches stored in Amazon S3
+          - gs:// for binary caches stored in Google Cloud Storage
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.nar-serve = {
+      description = "NAR server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      environment.PORT = toString cfg.port;
+      environment.NAR_CACHE_URL = cfg.cacheURL;
+
+      serviceConfig = {
+        Restart = "always";
+        RestartSec = "5s";
+        ExecStart = "${pkgs.nar-serve}/bin/nar-serve";
+        DynamicUser = true;
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/networking/nat.nix b/nixpkgs/nixos/modules/services/networking/nat.nix
index 21ae9eb8b6d4..45eb500fe8ce 100644
--- a/nixpkgs/nixos/modules/services/networking/nat.nix
+++ b/nixpkgs/nixos/modules/services/networking/nat.nix
@@ -9,7 +9,14 @@ with lib;
 let
   cfg = config.networking.nat;
 
-  dest = if cfg.externalIP == null then "-j MASQUERADE" else "-j SNAT --to-source ${cfg.externalIP}";
+  mkDest = externalIP: if externalIP == null
+                       then "-j MASQUERADE"
+                       else "-j SNAT --to-source ${externalIP}";
+  dest = mkDest cfg.externalIP;
+  destIPv6 = mkDest cfg.externalIPv6;
+
+  # Whether given IP (plus optional port) is an IPv6.
+  isIPv6 = ip: builtins.length (lib.splitString ":" ip) > 2;
 
   helpers = import ./helpers.nix { inherit config lib; };
 
@@ -28,63 +35,80 @@ let
     ${cfg.extraStopCommands}
   '';
 
-  setupNat = ''
-    ${helpers}
-    # Create subchain where we store rules
-    ip46tables -w -t nat -N nixos-nat-pre
-    ip46tables -w -t nat -N nixos-nat-post
-    ip46tables -w -t nat -N nixos-nat-out
-
+  mkSetupNat = { iptables, dest, internalIPs, forwardPorts }: ''
     # We can't match on incoming interface in POSTROUTING, so
     # mark packets coming from the internal interfaces.
     ${concatMapStrings (iface: ''
-      iptables -w -t nat -A nixos-nat-pre \
+      ${iptables} -w -t nat -A nixos-nat-pre \
         -i '${iface}' -j MARK --set-mark 1
     '') cfg.internalInterfaces}
 
     # NAT the marked packets.
     ${optionalString (cfg.internalInterfaces != []) ''
-      iptables -w -t nat -A nixos-nat-post -m mark --mark 1 \
+      ${iptables} -w -t nat -A nixos-nat-post -m mark --mark 1 \
         ${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 \
+      ${iptables} -w -t nat -A nixos-nat-post \
         -s '${range}' ${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} ${dest}
-    '') cfg.internalIPs}
+    '') internalIPs}
 
     # NAT from external ports to internal ports.
     ${concatMapStrings (fwd: ''
-      iptables -w -t nat -A nixos-nat-pre \
+      ${iptables} -w -t nat -A nixos-nat-pre \
         -i ${toString cfg.externalInterface} -p ${fwd.proto} \
         --dport ${builtins.toString fwd.sourcePort} \
         -j DNAT --to-destination ${fwd.destination}
 
       ${concatMapStrings (loopbackip:
         let
-          m                = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination;
-          destinationIP    = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0;
-          destinationPorts = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else builtins.replaceStrings ["-"] [":"] (elemAt m 1);
+          matchIP          = if isIPv6 fwd.destination then "[[]([0-9a-fA-F:]+)[]]" else "([0-9.]+)";
+          m                = builtins.match "${matchIP}:([0-9-]+)" fwd.destination;
+          destinationIP    = if m == null then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0;
+          destinationPorts = if m == null then throw "bad ip:ports `${fwd.destination}'" else builtins.replaceStrings ["-"] [":"] (elemAt m 1);
         in ''
           # Allow connections to ${loopbackip}:${toString fwd.sourcePort} from the host itself
-          iptables -w -t nat -A nixos-nat-out \
+          ${iptables} -w -t nat -A nixos-nat-out \
             -d ${loopbackip} -p ${fwd.proto} \
             --dport ${builtins.toString fwd.sourcePort} \
             -j DNAT --to-destination ${fwd.destination}
 
           # Allow connections to ${loopbackip}:${toString fwd.sourcePort} from other hosts behind NAT
-          iptables -w -t nat -A nixos-nat-pre \
+          ${iptables} -w -t nat -A nixos-nat-pre \
             -d ${loopbackip} -p ${fwd.proto} \
             --dport ${builtins.toString fwd.sourcePort} \
             -j DNAT --to-destination ${fwd.destination}
 
-          iptables -w -t nat -A nixos-nat-post \
+          ${iptables} -w -t nat -A nixos-nat-post \
             -d ${destinationIP} -p ${fwd.proto} \
             --dport ${destinationPorts} \
             -j SNAT --to-source ${loopbackip}
         '') fwd.loopbackIPs}
-    '') cfg.forwardPorts}
+    '') forwardPorts}
+  '';
+
+  setupNat = ''
+    ${helpers}
+    # Create subchains where we store rules
+    ip46tables -w -t nat -N nixos-nat-pre
+    ip46tables -w -t nat -N nixos-nat-post
+    ip46tables -w -t nat -N nixos-nat-out
+
+    ${mkSetupNat {
+      iptables = "iptables";
+      inherit dest;
+      inherit (cfg) internalIPs;
+      forwardPorts = filter (x: !(isIPv6 x.destination)) cfg.forwardPorts;
+    }}
+
+    ${optionalString cfg.enableIPv6 (mkSetupNat {
+      iptables = "ip6tables";
+      dest = destIPv6;
+      internalIPs = cfg.internalIPv6s;
+      forwardPorts = filter (x: isIPv6 x.destination) cfg.forwardPorts;
+    })}
 
     ${optionalString (cfg.dmzHost != null) ''
       iptables -w -t nat -A nixos-nat-pre \
@@ -117,6 +141,15 @@ in
         '';
     };
 
+    networking.nat.enableIPv6 = mkOption {
+      type = types.bool;
+      default = false;
+      description =
+        ''
+          Whether to enable IPv6 NAT.
+        '';
+    };
+
     networking.nat.internalInterfaces = mkOption {
       type = types.listOf types.str;
       default = [];
@@ -141,6 +174,18 @@ in
         '';
     };
 
+    networking.nat.internalIPv6s = mkOption {
+      type = types.listOf types.str;
+      default = [];
+      example = [ "fc00::/64" ];
+      description =
+        ''
+          The IPv6 address ranges for which to perform NAT.  Packets
+          coming from these addresses (on any interface) and destined
+          for the external interface will be rewritten.
+        '';
+    };
+
     networking.nat.externalInterface = mkOption {
       type = types.nullOr types.str;
       default = null;
@@ -164,6 +209,19 @@ in
         '';
     };
 
+    networking.nat.externalIPv6 = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      example = "2001:dc0:2001:11::175";
+      description =
+        ''
+          The public IPv6 address to which packets from the local
+          network are to be rewritten.  If this is left empty, the
+          IP address associated with the external interface will be
+          used.
+        '';
+    };
+
     networking.nat.forwardPorts = mkOption {
       type = with types; listOf (submodule {
         options = {
@@ -176,7 +234,7 @@ in
           destination = mkOption {
             type = types.str;
             example = "10.0.0.1:80";
-            description = "Forward connection to destination ip:port; to specify a port range, use ip:start-end";
+            description = "Forward connection to destination ip:port (or [ipv6]:port); to specify a port range, use ip:start-end";
           };
 
           proto = mkOption {
@@ -195,11 +253,15 @@ in
         };
       });
       default = [];
-      example = [ { sourcePort = 8080; destination = "10.0.0.1:80"; proto = "tcp"; } ];
+      example = [
+        { sourcePort = 8080; destination = "10.0.0.1:80"; proto = "tcp"; }
+        { sourcePort = 8080; destination = "[fc00::2]:80"; proto = "tcp"; }
+      ];
       description =
         ''
           List of forwarded ports from the external interface to
-          internal destinations by using DNAT.
+          internal destinations by using DNAT. Destination can be
+          IPv6 if IPv6 NAT is enabled.
         '';
     };
 
@@ -246,6 +308,9 @@ in
     (mkIf config.networking.nat.enable {
 
       assertions = [
+        { assertion = cfg.enableIPv6           -> config.networking.enableIPv6;
+          message = "networking.nat.enableIPv6 requires networking.enableIPv6";
+        }
         { assertion = (cfg.dmzHost != null)    -> (cfg.externalInterface != null);
           message = "networking.nat.dmzHost requires networking.nat.externalInterface";
         }
@@ -261,6 +326,15 @@ in
         kernel.sysctl = {
           "net.ipv4.conf.all.forwarding" = mkOverride 99 true;
           "net.ipv4.conf.default.forwarding" = mkOverride 99 true;
+        } // optionalAttrs cfg.enableIPv6 {
+          # Do not prevent IPv6 autoconfiguration.
+          # See <http://strugglers.net/~andy/blog/2011/09/04/linux-ipv6-router-advertisements-and-forwarding/>.
+          "net.ipv6.conf.all.accept_ra" = mkOverride 99 2;
+          "net.ipv6.conf.default.accept_ra" = mkOverride 99 2;
+
+          # Forward IPv6 packets.
+          "net.ipv6.conf.all.forwarding" = mkOverride 99 true;
+          "net.ipv6.conf.default.forwarding" = mkOverride 99 true;
         };
       };
 
diff --git a/nixpkgs/nixos/modules/services/networking/networkmanager.nix b/nixpkgs/nixos/modules/services/networking/networkmanager.nix
index 17c549d42c32..2e680544ec24 100644
--- a/nixpkgs/nixos/modules/services/networking/networkmanager.nix
+++ b/nixpkgs/nixos/modules/services/networking/networkmanager.nix
@@ -15,6 +15,7 @@ let
     networkmanager-openconnect
     networkmanager-openvpn
     networkmanager-vpnc
+    networkmanager-sstp
    ] ++ optional (!delegateWireless && !enableIwd) wpa_supplicant;
 
   delegateWireless = config.networking.wireless.enable == true && cfg.unmanaged != [];
@@ -386,6 +387,9 @@ in {
 
       "NetworkManager/VPN/nm-iodine-service.name".source =
         "${networkmanager-iodine}/lib/NetworkManager/VPN/nm-iodine-service.name";
+
+      "NetworkManager/VPN/nm-sstp-service.name".source =
+        "${networkmanager-sstp}/lib/NetworkManager/VPN/nm-sstp-service.name";
       }
       // optionalAttrs (cfg.appendNameservers != [] || cfg.insertNameservers != [])
          {
@@ -461,7 +465,7 @@ in {
       restartTriggers = [ configFile overrideNameserversScript ];
 
       # useful binaries for user-specified hooks
-      path = [ pkgs.iproute pkgs.utillinux pkgs.coreutils ];
+      path = [ pkgs.iproute pkgs.util-linux pkgs.coreutils ];
       aliases = [ "dbus-org.freedesktop.nm-dispatcher.service" ];
     };
 
diff --git a/nixpkgs/nixos/modules/services/networking/nextdns.nix b/nixpkgs/nixos/modules/services/networking/nextdns.nix
index a633bff62ec7..b070eeec894f 100644
--- a/nixpkgs/nixos/modules/services/networking/nextdns.nix
+++ b/nixpkgs/nixos/modules/services/networking/nextdns.nix
@@ -28,9 +28,9 @@ in {
       environment = {
         SERVICE_RUN_MODE = "1";
       };
+      startLimitIntervalSec = 5;
+      startLimitBurst = 10;
       serviceConfig = {
-        StartLimitInterval = 5;
-        StartLimitBurst = 10;
         ExecStart = "${pkgs.nextdns}/bin/nextdns run ${escapeShellArgs config.services.nextdns.arguments}";
         RestartSec = 120;
         LimitMEMLOCK = "infinity";
diff --git a/nixpkgs/nixos/modules/services/networking/nftables.nix b/nixpkgs/nixos/modules/services/networking/nftables.nix
index ec9d9753cfe2..cb75142965ea 100644
--- a/nixpkgs/nixos/modules/services/networking/nftables.nix
+++ b/nixpkgs/nixos/modules/services/networking/nftables.nix
@@ -99,7 +99,7 @@ in
   config = mkIf cfg.enable {
     assertions = [{
       assertion = config.networking.firewall.enable == false;
-      message = "You can not use nftables with services.networking.firewall.";
+      message = "You can not use nftables and iptables at the same time. networking.firewall.enable must be set to false.";
     }];
     boot.blacklistedKernelModules = [ "ip_tables" ];
     environment.systemPackages = [ pkgs.nftables ];
diff --git a/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix b/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix
index 3f2ce5bca4da..0012302db2e3 100644
--- a/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix
+++ b/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix
@@ -42,9 +42,9 @@ in
       description = "A HTTP nix store that proxies requests to Google Storage";
       wantedBy = ["multi-user.target"];
 
+      startLimitIntervalSec = 10;
       serviceConfig = {
         RestartSec = 5;
-        StartLimitInterval = 10;
         ExecStart = ''
           ${pkgs.nix-store-gcs-proxy}/bin/nix-store-gcs-proxy \
             --bucket-name ${cfg.bucketName} \
diff --git a/nixpkgs/nixos/modules/services/networking/nsd.nix b/nixpkgs/nixos/modules/services/networking/nsd.nix
index 3ecbd06ee416..f33c350a257a 100644
--- a/nixpkgs/nixos/modules/services/networking/nsd.nix
+++ b/nixpkgs/nixos/modules/services/networking/nsd.nix
@@ -916,14 +916,14 @@ in
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
 
+      startLimitBurst = 4;
+      startLimitIntervalSec = 5 * 60;  # 5 mins
       serviceConfig = {
         ExecStart = "${nsdPkg}/sbin/nsd -d -c ${nsdEnv}/nsd.conf";
         StandardError = "null";
         PIDFile = pidFile;
         Restart = "always";
         RestartSec = "4s";
-        StartLimitBurst = 4;
-        StartLimitInterval = "5min";
       };
 
       preStart = ''
diff --git a/nixpkgs/nixos/modules/services/networking/ntp/chrony.nix b/nixpkgs/nixos/modules/services/networking/ntp/chrony.nix
index 78de50583f34..e6fa48daf46c 100644
--- a/nixpkgs/nixos/modules/services/networking/ntp/chrony.nix
+++ b/nixpkgs/nixos/modules/services/networking/ntp/chrony.nix
@@ -6,6 +6,7 @@ let
   cfg = config.services.chrony;
 
   stateDir = "/var/lib/chrony";
+  driftFile = "${stateDir}/chrony.drift";
   keyFile = "${stateDir}/chrony.keys";
 
   configFile = pkgs.writeText "chrony.conf" ''
@@ -16,7 +17,7 @@ let
       "initstepslew ${toString cfg.initstepslew.threshold} ${concatStringsSep " " cfg.servers}"
     }
 
-    driftfile ${stateDir}/chrony.drift
+    driftfile ${driftFile}
     keyfile ${keyFile}
 
     ${optionalString (!config.time.hardwareClockInLocalTime) "rtconutc"}
@@ -95,6 +96,7 @@ in
 
     systemd.tmpfiles.rules = [
       "d ${stateDir} 0755 chrony chrony - -"
+      "f ${driftFile} 0640 chrony chrony -"
       "f ${keyFile} 0640 chrony chrony -"
     ];
 
diff --git a/nixpkgs/nixos/modules/services/networking/pdns-recursor.nix b/nixpkgs/nixos/modules/services/networking/pdns-recursor.nix
index 6ff181377fcc..a326eccfd65d 100644
--- a/nixpkgs/nixos/modules/services/networking/pdns-recursor.nix
+++ b/nixpkgs/nixos/modules/services/networking/pdns-recursor.nix
@@ -3,9 +3,6 @@
 with lib;
 
 let
-  dataDir  = "/var/lib/pdns-recursor";
-  username = "pdns-recursor";
-
   cfg = config.services.pdns-recursor;
 
   oneOrMore  = type: with types; either type (listOf type);
@@ -21,7 +18,7 @@ let
     else if builtins.isList val then (concatMapStringsSep "," serialize val)
     else "";
 
-  configFile = pkgs.writeText "recursor.conf"
+  configDir = pkgs.writeTextDir "recursor.conf"
     (concatStringsSep "\n"
       (flip mapAttrsToList cfg.settings
         (name: val: "${name}=${serialize val}")));
@@ -173,45 +170,30 @@ in {
       serve-rfc1918    = cfg.serveRFC1918;
       lua-config-file  = pkgs.writeText "recursor.lua" cfg.luaConfig;
 
+      daemon         = false;
+      write-pid      = false;
       log-timestamp  = false;
       disable-syslog = true;
     };
 
-    users.users.${username} = {
-      home = dataDir;
-      createHome = true;
-      uid = config.ids.uids.pdns-recursor;
-      description = "PowerDNS Recursor daemon user";
-    };
+    systemd.packages = [ pkgs.pdns-recursor ];
 
     systemd.services.pdns-recursor = {
-      unitConfig.Documentation = "man:pdns_recursor(1) man:rec_control(1)";
-      description = "PowerDNS recursive server";
       wantedBy = [ "multi-user.target" ];
-      after    = [ "network.target" ];
 
       serviceConfig = {
-        User = username;
-        Restart    ="on-failure";
-        RestartSec = "5";
-        PrivateTmp = true;
-        PrivateDevices = true;
-        AmbientCapabilities = "cap_net_bind_service";
-        ExecStart = ''${pkgs.pdns-recursor}/bin/pdns_recursor \
-          --config-dir=${dataDir} \
-          --socket-dir=${dataDir}
-        '';
+        ExecStart = [ "" "${pkgs.pdns-recursor}/bin/pdns_recursor --config-dir=${configDir}" ];
       };
+    };
 
-      preStart = ''
-        # Link configuration file into recursor home directory
-        configPath=${dataDir}/recursor.conf
-        if [ "$(realpath $configPath)" != "${configFile}" ]; then
-          rm -f $configPath
-          ln -s ${configFile} $configPath
-        fi
-      '';
+    users.users.pdns-recursor = {
+      isSystemUser = true;
+      group = "pdns-recursor";
+      description = "PowerDNS Recursor daemon user";
     };
+
+    users.groups.pdns-recursor = {};
+
   };
 
   imports = [
diff --git a/nixpkgs/nixos/modules/services/networking/powerdns.nix b/nixpkgs/nixos/modules/services/networking/powerdns.nix
index ba05e15389f6..8cae61b83543 100644
--- a/nixpkgs/nixos/modules/services/networking/powerdns.nix
+++ b/nixpkgs/nixos/modules/services/networking/powerdns.nix
@@ -8,42 +8,40 @@ let
 in {
   options = {
     services.powerdns = {
-      enable = mkEnableOption "Powerdns domain name server";
+      enable = mkEnableOption "PowerDNS domain name server";
 
       extraConfig = mkOption {
         type = types.lines;
         default = "launch=bind";
         description = ''
-          Extra lines to be added verbatim to pdns.conf.
-          Powerdns will chroot to /var/lib/powerdns.
-          So any file, powerdns is supposed to be read,
-          should be in /var/lib/powerdns and needs to specified
-          relative to the chroot.
+          PowerDNS configuration. Refer to
+          <link xlink:href="https://doc.powerdns.com/authoritative/settings.html"/>
+          for details on supported values.
         '';
       };
     };
   };
 
-  config = mkIf config.services.powerdns.enable {
+  config = mkIf cfg.enable {
+
+    systemd.packages = [ pkgs.powerdns ];
+
     systemd.services.pdns = {
-      unitConfig.Documentation = "man:pdns_server(1) man:pdns_control(1)";
-      description = "Powerdns name server";
       wantedBy = [ "multi-user.target" ];
-      after = ["network.target" "mysql.service" "postgresql.service" "openldap.service"];
+      after = [ "network.target" "mysql.service" "postgresql.service" "openldap.service" ];
 
       serviceConfig = {
-        Restart="on-failure";
-        RestartSec="1";
-        StartLimitInterval="0";
-        PrivateDevices=true;
-        CapabilityBoundingSet="CAP_CHOWN CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT";
-        NoNewPrivileges=true;
-        ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/lib/powerdns";
-        ExecStart = "${pkgs.powerdns}/bin/pdns_server --setuid=nobody --setgid=nogroup --chroot=/var/lib/powerdns --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${configDir}";
-        ProtectSystem="full";
-        ProtectHome=true;
-        RestrictAddressFamilies="AF_UNIX AF_INET AF_INET6";
+        ExecStart = [ "" "${pkgs.powerdns}/bin/pdns_server --config-dir=${configDir} --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no" ];
       };
     };
+
+    users.users.pdns = {
+      isSystemUser = true;
+      group = "pdns";
+      description = "PowerDNS";
+    };
+
+    users.groups.pdns = {};
+
   };
 }
diff --git a/nixpkgs/nixos/modules/services/networking/privoxy.nix b/nixpkgs/nixos/modules/services/networking/privoxy.nix
index 1f41c720adf5..e3b34cb0c616 100644
--- a/nixpkgs/nixos/modules/services/networking/privoxy.nix
+++ b/nixpkgs/nixos/modules/services/networking/privoxy.nix
@@ -8,15 +8,22 @@ let
 
   cfg = config.services.privoxy;
 
-  confFile = pkgs.writeText "privoxy.conf" ''
+  confFile = pkgs.writeText "privoxy.conf" (''
     user-manual ${privoxy}/share/doc/privoxy/user-manual
     confdir ${privoxy}/etc/
     listen-address  ${cfg.listenAddress}
     enable-edit-actions ${if (cfg.enableEditActions == true) then "1" else "0"}
     ${concatMapStrings (f: "actionsfile ${f}\n") cfg.actionsFiles}
     ${concatMapStrings (f: "filterfile ${f}\n") cfg.filterFiles}
+  '' + optionalString cfg.enableTor ''
+    forward-socks4a / ${config.services.tor.client.socksListenAddressFaster} .
+    toggle 1
+    enable-remote-toggle 0
+    enable-edit-actions 0
+    enable-remote-http-toggle 0
+  '' + ''
     ${cfg.extraConfig}
-  '';
+  '');
 
 in
 
@@ -72,6 +79,15 @@ in
         '';
       };
 
+      enableTor = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to configure Privoxy to use Tor's faster SOCKS port,
+          suitable for HTTP.
+        '';
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         default = "" ;
diff --git a/nixpkgs/nixos/modules/services/networking/prosody.nix b/nixpkgs/nixos/modules/services/networking/prosody.nix
index a6c1cb0f4797..e7a7aa700be6 100644
--- a/nixpkgs/nixos/modules/services/networking/prosody.nix
+++ b/nixpkgs/nixos/modules/services/networking/prosody.nix
@@ -261,7 +261,7 @@ let
 
   toLua = x:
     if builtins.isString x then ''"${x}"''
-    else if builtins.isBool x then (if x == true then "true" else "false")
+    else if builtins.isBool x then boolToString x
     else if builtins.isInt x then toString x
     else if builtins.isList x then ''{ ${lib.concatStringsSep ", " (map (n: toLua n) x) } }''
     else throw "Invalid Lua value";
diff --git a/nixpkgs/nixos/modules/services/networking/shellhub-agent.nix b/nixpkgs/nixos/modules/services/networking/shellhub-agent.nix
new file mode 100644
index 000000000000..4ce4b8250bc3
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/shellhub-agent.nix
@@ -0,0 +1,91 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.services.shellhub-agent;
+in {
+
+  ###### interface
+
+  options = {
+
+    services.shellhub-agent = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the ShellHub Agent daemon, which allows
+          secure remote logins.
+        '';
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.shellhub-agent;
+        defaultText = "pkgs.shellhub-agent";
+        description = ''
+          Which ShellHub Agent package to use.
+        '';
+      };
+
+      tenantId = mkOption {
+        type = types.str;
+        example = "ba0a880c-2ada-11eb-a35e-17266ef329d6";
+        description = ''
+          The tenant ID to use when connecting to the ShellHub
+          Gateway.
+        '';
+      };
+
+      server = mkOption {
+        type = types.str;
+        default = "https://cloud.shellhub.io";
+        description = ''
+          Server address of ShellHub Gateway to connect.
+        '';
+      };
+
+      privateKey = mkOption {
+        type = types.path;
+        default = "/var/lib/shellhub-agent/private.key";
+        description = ''
+          Location where to store the ShellHub Agent private
+          key.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.shellhub-agent = {
+      description = "ShellHub Agent";
+
+      wantedBy = [ "multi-user.target" ];
+      requires = [ "local-fs.target" ];
+      wants = [ "network-online.target" ];
+      after = [
+        "local-fs.target"
+        "network.target"
+        "network-online.target"
+        "time-sync.target"
+      ];
+
+      environment.SERVER_ADDRESS = cfg.server;
+      environment.PRIVATE_KEY = cfg.privateKey;
+      environment.TENANT_ID = cfg.tenantId;
+
+      serviceConfig = {
+        # The service starts sessions for different users.
+        User = "root";
+        Restart = "on-failure";
+        ExecStart = "${cfg.package}/bin/agent";
+      };
+    };
+
+    environment.systemPackages = [ cfg.package ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
index d0251277e9e8..174c80f73d2d 100644
--- a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
@@ -269,6 +269,7 @@ in
       kexAlgorithms = mkOption {
         type = types.listOf types.str;
         default = [
+          "curve25519-sha256"
           "curve25519-sha256@libssh.org"
           "diffie-hellman-group-exchange-sha256"
         ];
@@ -279,7 +280,7 @@ in
           Defaults to recommended settings from both
           <link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
           and
-          <link xlink:href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29" />
+          <link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" />
         '';
       };
 
@@ -300,7 +301,7 @@ in
           Defaults to recommended settings from both
           <link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
           and
-          <link xlink:href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29" />
+          <link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" />
         '';
       };
 
@@ -321,7 +322,7 @@ in
           Defaults to recommended settings from both
           <link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
           and
-          <link xlink:href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29" />
+          <link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" />
         '';
       };
 
@@ -487,7 +488,7 @@ in
     # 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" ];
+      [ "%h/.ssh/authorized_keys" "%h/.ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ];
 
     services.openssh.extraConfig = mkOrder 0
       ''
diff --git a/nixpkgs/nixos/modules/services/networking/sslh.nix b/nixpkgs/nixos/modules/services/networking/sslh.nix
index 0921febba668..4c2740d20192 100644
--- a/nixpkgs/nixos/modules/services/networking/sslh.nix
+++ b/nixpkgs/nixos/modules/services/networking/sslh.nix
@@ -31,7 +31,7 @@ let
       { name: "openvpn"; host: "localhost"; port: "1194"; probe: "builtin"; },
       { name: "xmpp"; host: "localhost"; port: "5222"; probe: "builtin"; },
       { name: "http"; host: "localhost"; port: "80"; probe: "builtin"; },
-      { name: "ssl"; host: "localhost"; port: "443"; probe: "builtin"; },
+      { name: "tls"; host: "localhost"; port: "443"; probe: "builtin"; },
       { name: "anyprot"; host: "localhost"; port: "443"; probe: "builtin"; }
     );
   '';
diff --git a/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix b/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix
index 0fec3ef00ad9..f67eedac2961 100644
--- a/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix
+++ b/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix
@@ -63,7 +63,7 @@ in  {
       description = "strongSwan IPsec IKEv1/IKEv2 daemon using swanctl";
       wantedBy = [ "multi-user.target" ];
       after    = [ "network-online.target" ];
-      path     = with pkgs; [ kmod iproute iptables utillinux ];
+      path     = with pkgs; [ kmod iproute iptables util-linux ];
       environment = {
         STRONGSWAN_CONF = pkgs.writeTextFile {
           name = "strongswan.conf";
diff --git a/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix b/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix
index 808cb863a9cf..1d1e0bd1ca19 100644
--- a/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix
+++ b/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix
@@ -1173,20 +1173,20 @@ in {
 
     ppk = mkPrefixedAttrsOfParams {
       secret = mkOptionalStrParam ''
-	      Value of the PPK. It may either be an ASCII string, a hex encoded string
-	      if it has a <literal>0x</literal> prefix or a Base64 encoded string if
-	      it has a <literal>0s</literal> prefix in its value. Should have at least
-	      256 bits of entropy for 128-bit security.
+        Value of the PPK. It may either be an ASCII string, a hex encoded string
+        if it has a <literal>0x</literal> prefix or a Base64 encoded string if
+        it has a <literal>0s</literal> prefix in its value. Should have at least
+        256 bits of entropy for 128-bit security.
       '';
 
       id = mkPrefixedAttrsOfParam (mkOptionalStrParam "") ''
-	      PPK identity the PPK belongs to. Multiple unique identities may be
-	      specified, each having an <literal>id</literal> prefix, if a secret is
-	      shared between multiple peers.
+        PPK identity the PPK belongs to. Multiple unique identities may be
+        specified, each having an <literal>id</literal> prefix, if a secret is
+        shared between multiple peers.
       '';
     } ''
-	    Postquantum Preshared Key (PPK) section for a specific secret. Each PPK is
-	    defined in a unique section having the <literal>ppk</literal> prefix.
+      Postquantum Preshared Key (PPK) section for a specific secret. Each PPK is
+      defined in a unique section having the <literal>ppk</literal> prefix.
     '';
 
     private = mkPrefixedAttrsOfParams {
diff --git a/nixpkgs/nixos/modules/services/networking/strongswan.nix b/nixpkgs/nixos/modules/services/networking/strongswan.nix
index 13a1a897c5ed..f6170b813654 100644
--- a/nixpkgs/nixos/modules/services/networking/strongswan.nix
+++ b/nixpkgs/nixos/modules/services/networking/strongswan.nix
@@ -152,7 +152,7 @@ in
     systemd.services.strongswan = {
       description = "strongSwan IPSec Service";
       wantedBy = [ "multi-user.target" ];
-      path = with pkgs; [ kmod iproute iptables utillinux ]; # XXX Linux
+      path = with pkgs; [ kmod iproute iptables util-linux ]; # XXX Linux
       after = [ "network-online.target" ];
       environment = {
         STRONGSWAN_CONF = strongswanConf { inherit setup connections ca secretsFile managePlugins enabledPlugins; };
diff --git a/nixpkgs/nixos/modules/services/networking/stunnel.nix b/nixpkgs/nixos/modules/services/networking/stunnel.nix
index ab51bba2f6ac..fe1616f411f0 100644
--- a/nixpkgs/nixos/modules/services/networking/stunnel.nix
+++ b/nixpkgs/nixos/modules/services/networking/stunnel.nix
@@ -16,8 +16,12 @@ let
   serverConfig = {
     options = {
       accept = mkOption {
-        type = types.int;
-        description = "On which port stunnel should listen for incoming TLS connections.";
+        type = types.either types.str types.int;
+        description = ''
+          On which [host:]port stunnel should listen for incoming TLS connections.
+          Note that unlike other softwares stunnel ipv6 address need no brackets,
+          so to listen on all IPv6 addresses on port 1234 one would use ':::1234'.
+        '';
       };
 
       connect = mkOption {
@@ -129,7 +133,6 @@ in
         type = with types; attrsOf (submodule serverConfig);
         example = {
           fancyWebserver = {
-            enable = true;
             accept = 443;
             connect = 8080;
             cert = "/path/to/pem/file";
diff --git a/nixpkgs/nixos/modules/services/networking/supybot.nix b/nixpkgs/nixos/modules/services/networking/supybot.nix
index dc9fb31ffd0b..7a62e04ec7c4 100644
--- a/nixpkgs/nixos/modules/services/networking/supybot.nix
+++ b/nixpkgs/nixos/modules/services/networking/supybot.nix
@@ -103,6 +103,8 @@ in
         rm -f '${cfg.stateDir}/supybot.cfg.bak'
       '';
 
+      startLimitIntervalSec = 5 * 60;  # 5 min
+      startLimitBurst = 1;
       serviceConfig = {
         ExecStart = "${pyEnv}/bin/supybot ${cfg.stateDir}/supybot.cfg";
         PIDFile = "/run/supybot.pid";
@@ -110,8 +112,6 @@ in
         Group = "supybot";
         UMask = "0007";
         Restart = "on-abort";
-        StartLimitInterval = "5m";
-        StartLimitBurst = "1";
 
         NoNewPrivileges = true;
         PrivateDevices = true;
diff --git a/nixpkgs/nixos/modules/services/networking/tailscale.nix b/nixpkgs/nixos/modules/services/networking/tailscale.nix
index 4d6aeb75ebd1..1a1474595beb 100644
--- a/nixpkgs/nixos/modules/services/networking/tailscale.nix
+++ b/nixpkgs/nixos/modules/services/networking/tailscale.nix
@@ -14,36 +14,21 @@ in {
       default = 41641;
       description = "The port to listen on for tunnel traffic (0=autoselect).";
     };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.tailscale;
+      defaultText = "pkgs.tailscale";
+      description = "The package to use for tailscale";
+    };
   };
 
   config = mkIf cfg.enable {
-    systemd.services.tailscale = {
-      description = "Tailscale client daemon";
-
-      after = [ "network-pre.target" ];
-      wants = [ "network-pre.target" ];
+    environment.systemPackages = [ cfg.package ]; # for the CLI
+    systemd.packages = [ cfg.package ];
+    systemd.services.tailscaled = {
       wantedBy = [ "multi-user.target" ];
-
-      unitConfig = {
-        StartLimitIntervalSec = 0;
-        StartLimitBurst = 0;
-      };
-
-      serviceConfig = {
-        ExecStart =
-          "${pkgs.tailscale}/bin/tailscaled --port ${toString cfg.port}";
-
-        RuntimeDirectory = "tailscale";
-        RuntimeDirectoryMode = 755;
-
-        StateDirectory = "tailscale";
-        StateDirectoryMode = 750;
-
-        CacheDirectory = "tailscale";
-        CacheDirectoryMode = 750;
-
-        Restart = "on-failure";
-      };
+      serviceConfig.Environment = "PORT=${toString cfg.port}";
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/networking/tinc.nix b/nixpkgs/nixos/modules/services/networking/tinc.nix
index 725bd9bf9403..b6afd83a9abd 100644
--- a/nixpkgs/nixos/modules/services/networking/tinc.nix
+++ b/nixpkgs/nixos/modules/services/networking/tinc.nix
@@ -1,13 +1,156 @@
 { config, lib, pkgs, ... }:
 
 with lib;
-
 let
-
   cfg = config.services.tinc;
 
-in
+  mkValueString = value:
+    if value == true then "yes"
+    else if value == false then "no"
+    else generators.mkValueStringDefault { } value;
+
+  toTincConf = generators.toKeyValue {
+    listsAsDuplicateKeys = true;
+    mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } "=";
+  };
+
+  tincConfType = with types;
+    let
+      valueType = oneOf [ bool str int ];
+    in
+    attrsOf (either valueType (listOf valueType));
+
+  addressSubmodule = {
+    options = {
+      address = mkOption {
+        type = types.str;
+        description = "The external IP address or hostname where the host can be reached.";
+      };
+
+      port = mkOption {
+        type = types.nullOr types.port;
+        default = null;
+        description = ''
+          The port where the host can be reached.
+
+          If no port is specified, the default Port is used.
+        '';
+      };
+    };
+  };
+
+  subnetSubmodule = {
+    options = {
+      address = mkOption {
+        type = types.str;
+        description = ''
+          The subnet of this host.
+
+          Subnets can either be single MAC, IPv4 or IPv6 addresses, in which case
+          a subnet consisting of only that single address is assumed, or they can
+          be a IPv4 or IPv6 network address with a prefix length.
+
+          IPv4 subnets are notated like 192.168.1.0/24, IPv6 subnets are notated
+          like fec0:0:0:1::/64. MAC addresses are notated like 0:1a:2b:3c:4d:5e.
+
+          Note that subnets like 192.168.1.1/24 are invalid.
+        '';
+      };
+
+      prefixLength = mkOption {
+        type = with types; nullOr (addCheck int (n: n >= 0 && n <= 128));
+        default = null;
+        description = ''
+          The prefix length of the subnet.
+
+          If null, a subnet consisting of only that single address is assumed.
+
+          This conforms to standard CIDR notation as described in RFC1519.
+        '';
+      };
+
+      weight = mkOption {
+        type = types.ints.unsigned;
+        default = 10;
+        description = ''
+          Indicates the priority over identical Subnets owned by different nodes.
+
+          Lower values indicate higher priority. Packets will be sent to the
+          node with the highest priority, unless that node is not reachable, in
+          which case the node with the next highest priority will be tried, and
+          so on.
+        '';
+      };
+    };
+  };
+
+  hostSubmodule = { config, ... }: {
+    options = {
+      addresses = mkOption {
+        type = types.listOf (types.submodule addressSubmodule);
+        default = [ ];
+        description = ''
+          The external address where the host can be reached. This will set this
+          host's <option>settings.Address</option> option.
+
+          This variable is only required if you want to connect to this host.
+        '';
+      };
+
+      subnets = mkOption {
+        type = types.listOf (types.submodule subnetSubmodule);
+        default = [ ];
+        description = ''
+          The subnets which this tinc daemon will serve. This will set this
+          host's <option>settings.Subnet</option> option.
 
+          Tinc tries to look up which other daemon it should send a packet to by
+          searching the appropriate subnet. If the packet matches a subnet, it
+          will be sent to the daemon who has this subnet in his host
+          configuration file.
+        '';
+      };
+
+      rsaPublicKey = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Legacy RSA public key of the host in PEM format, including start and
+          end markers.
+
+          This will be appended as-is in the host's configuration file.
+
+          The ed25519 public key can be specified using the
+          <option>settings.Ed25519PublicKey</option> option instead.
+        '';
+      };
+
+      settings = mkOption {
+        default = { };
+        type = types.submodule { freeformType = tincConfType; };
+        description = ''
+          Configuration for this host.
+
+          See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Host-configuration-variables.html"/>
+          for supported values.
+        '';
+      };
+    };
+
+    config.settings = {
+      Address = mkDefault (map
+        (address: "${address.address} ${toString address.port}")
+        config.addresses);
+
+      Subnet = mkDefault (map
+        (subnet:
+          if subnet.prefixLength == null then "${subnet.address}#${toString subnet.weight}"
+          else "${subnet.address}/${toString subnet.prefixLength}#${toString subnet.weight}")
+        config.subnets);
+    };
+  };
+
+in
 {
 
   ###### interface
@@ -18,7 +161,7 @@ in
 
       networks = mkOption {
         default = { };
-        type = with types; attrsOf (submodule {
+        type = with types; attrsOf (submodule ({ config, ... }: {
           options = {
 
             extraConfig = mkOption {
@@ -26,6 +169,9 @@ in
               type = types.lines;
               description = ''
                 Extra lines to add to the tinc service configuration file.
+
+                Note that using the declarative <option>service.tinc.networks.&lt;name&gt;.settings</option>
+                option is preferred.
               '';
             };
 
@@ -72,6 +218,40 @@ in
               description = ''
                 The name of the host in the network as well as the configuration for that host.
                 This name should only contain alphanumerics and underscores.
+
+                Note that using the declarative <option>service.tinc.networks.&lt;name&gt;.hostSettings</option>
+                option is preferred.
+              '';
+            };
+
+            hostSettings = mkOption {
+              default = { };
+              example = literalExample ''
+                {
+                  host1 = {
+                    addresses = [
+                      { address = "192.168.1.42"; }
+                      { address = "192.168.1.42"; port = 1655; }
+                    ];
+                    subnets = [ { address = "10.0.0.42"; } ];
+                    rsaPublicKey = "...";
+                    settings = {
+                      Ed25519PublicKey = "...";
+                    };
+                  };
+                  host2 = {
+                    subnets = [ { address = "10.0.1.0"; prefixLength = 24; weight = 2; } ];
+                    rsaPublicKey = "...";
+                    settings = {
+                      Compression = 10;
+                    };
+                  };
+                }
+              '';
+              type = types.attrsOf (types.submodule hostSubmodule);
+              description = ''
+                The name of the host in the network as well as the configuration for that host.
+                This name should only contain alphanumerics and underscores.
               '';
             };
 
@@ -79,7 +259,7 @@ in
               default = "tun";
               type = types.enum [ "tun" "tap" ];
               description = ''
-                The type of virtual interface used for the network connection
+                The type of virtual interface used for the network connection.
               '';
             };
 
@@ -118,8 +298,44 @@ in
                 Note that tinc can't run scripts anymore (such as tinc-down or host-up), unless it is setup to be runnable inside chroot environment.
               '';
             };
+
+            settings = mkOption {
+              default = { };
+              type = types.submodule { freeformType = tincConfType; };
+              example = literalExample ''
+                {
+                  Interface = "custom.interface";
+                  DirectOnly = true;
+                  Mode = "switch";
+                }
+              '';
+              description = ''
+                Configuration of the Tinc daemon for this network.
+
+                See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Main-configuration-variables.html"/>
+                for supported values.
+              '';
+            };
+          };
+
+          config = {
+            hosts = mapAttrs
+              (hostname: host: ''
+                ${toTincConf host.settings}
+                ${host.rsaPublicKey}
+              '')
+              config.hostSettings;
+
+            settings = {
+              DeviceType = mkDefault config.interfaceType;
+              Name = mkDefault (if config.name == null then "$HOST" else config.name);
+              Ed25519PrivateKeyFile = mkIf (config.ed25519PrivateKeyFile != null) (mkDefault config.ed25519PrivateKeyFile);
+              PrivateKeyFile = mkIf (config.rsaPrivateKeyFile != null) (mkDefault config.rsaPrivateKeyFile);
+              ListenAddress = mkIf (config.listenAddress != null) (mkDefault config.listenAddress);
+              BindToAddress = mkIf (config.bindToAddress != null) (mkDefault config.bindToAddress);
+            };
           };
-        });
+        }));
 
         description = ''
           Defines the tinc networks which will be started.
@@ -144,13 +360,7 @@ in
           "tinc/${network}/tinc.conf" = {
             mode = "0444";
             text = ''
-              Name = ${if data.name == null then "$HOST" else data.name}
-              DeviceType = ${data.interfaceType}
-              ${optionalString (data.ed25519PrivateKeyFile != null) "Ed25519PrivateKeyFile = ${data.ed25519PrivateKeyFile}"}
-              ${optionalString (data.rsaPrivateKeyFile != null) "PrivateKeyFile = ${data.rsaPrivateKeyFile}"}
-              ${optionalString (data.listenAddress != null) "ListenAddress = ${data.listenAddress}"}
-              ${optionalString (data.bindToAddress != null) "BindToAddress = ${data.bindToAddress}"}
-              Interface = tinc.${network}
+              ${toTincConf ({ Interface = "tinc.${network}"; } // data.settings)}
               ${data.extraConfig}
             '';
           };
@@ -168,6 +378,7 @@ in
           Type = "simple";
           Restart = "always";
           RestartSec = "3";
+          ExecReload = mkIf (versionAtLeast (getVersion data.package) "1.1pre") "${data.package}/bin/tinc -n ${network} reload";
           ExecStart = "${data.package}/bin/tincd -D -U tinc.${network} -n ${network} ${optionalString (data.chroot) "-R"} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel}";
         };
         preStart = ''
@@ -221,4 +432,5 @@ in
 
   };
 
+  meta.maintainers = with maintainers; [ minijackson ];
 }
diff --git a/nixpkgs/nixos/modules/services/networking/unbound.nix b/nixpkgs/nixos/modules/services/networking/unbound.nix
index baed83591e1e..622c3d8ea434 100644
--- a/nixpkgs/nixos/modules/services/networking/unbound.nix
+++ b/nixpkgs/nixos/modules/services/networking/unbound.nix
@@ -1,9 +1,7 @@
 { config, lib, pkgs, ... }:
 
 with lib;
-
 let
-
   cfg = config.services.unbound;
 
   stateDir = "/var/lib/unbound";
@@ -17,12 +15,12 @@ let
   forward =
     optionalString (any isLocalAddress cfg.forwardAddresses) ''
       do-not-query-localhost: no
-    '' +
-    optionalString (cfg.forwardAddresses != []) ''
+    ''
+    + optionalString (cfg.forwardAddresses != []) ''
       forward-zone:
         name: .
-    '' +
-    concatMapStringsSep "\n" (x: "    forward-addr: ${x}") cfg.forwardAddresses;
+    ''
+    + concatMapStringsSep "\n" (x: "    forward-addr: ${x}") cfg.forwardAddresses;
 
   rootTrustAnchorFile = "${stateDir}/root.key";
 
@@ -31,19 +29,25 @@ let
 
   confFile = pkgs.writeText "unbound.conf" ''
     server:
+      ip-freebind: yes
       directory: "${stateDir}"
       username: unbound
-      chroot: "${stateDir}"
+      chroot: ""
       pidfile: ""
+      # when running under systemd there is no need to daemonize
+      do-daemonize: no
       ${interfaces}
       ${access}
       ${trustAnchor}
+    ${lib.optionalString (cfg.localControlSocketPath != null) ''
+      remote-control:
+        control-enable: yes
+        control-interface: ${cfg.localControlSocketPath}
+    ''}
     ${cfg.extraConfig}
     ${forward}
   '';
-
 in
-
 {
 
   ###### interface
@@ -55,8 +59,8 @@ in
 
       package = mkOption {
         type = types.package;
-        default = pkgs.unbound;
-        defaultText = "pkgs.unbound";
+        default = pkgs.unbound-with-systemd;
+        defaultText = "pkgs.unbound-with-systemd";
         description = "The unbound package to use";
       };
 
@@ -69,11 +73,14 @@ in
       interfaces = mkOption {
         default = [ "127.0.0.1" ] ++ optional config.networking.enableIPv6 "::1";
         type = types.listOf types.str;
-        description = "What addresses the server should listen on.";
+        description =  ''
+          What addresses the server should listen on. This supports the interface syntax documented in
+          <citerefentry><refentrytitle>unbound.conf</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+        '';
       };
 
       forwardAddresses = mkOption {
-        default = [ ];
+        default = [];
         type = types.listOf types.str;
         description = "What servers to forward queries to.";
       };
@@ -84,6 +91,28 @@ in
         description = "Use and update root trust anchor for DNSSEC validation.";
       };
 
+      localControlSocketPath = mkOption {
+        default = null;
+        # FIXME: What is the proper type here so users can specify strings,
+        # paths and null?
+        # My guess would be `types.nullOr (types.either types.str types.path)`
+        # but I haven't verified yet.
+        type = types.nullOr types.str;
+        example = "/run/unbound/unbound.ctl";
+        description = ''
+          When not set to <literal>null</literal> this option defines the path
+          at which the unbound remote control socket should be created at. The
+          socket will be owned by the unbound user (<literal>unbound</literal>)
+          and group will be <literal>nogroup</literal>.
+
+          Users that should be permitted to access the socket must be in the
+          <literal>unbound</literal> group.
+
+          If this option is <literal>null</literal> remote control will not be
+          configured at all. Unbounds default values apply.
+        '';
+      };
+
       extraConfig = mkOption {
         default = "";
         type = types.lines;
@@ -106,43 +135,85 @@ in
     users.users.unbound = {
       description = "unbound daemon user";
       isSystemUser = true;
+      group = lib.mkIf (cfg.localControlSocketPath != null) (lib.mkDefault "unbound");
+    };
+
+    # We need a group so that we can give users access to the configured
+    # control socket. Unbound allows access to the socket only to the unbound
+    # user and the primary group.
+    users.groups = lib.mkIf (cfg.localControlSocketPath != null) {
+      unbound = {};
     };
 
     networking.resolvconf.useLocalResolver = mkDefault true;
 
+
+    environment.etc."unbound/unbound.conf".source = confFile;
+
     systemd.services.unbound = {
       description = "Unbound recursive Domain Name Server";
       after = [ "network.target" ];
       before = [ "nss-lookup.target" ];
-      wants = [ "nss-lookup.target" ];
-      wantedBy = [ "multi-user.target" ];
-
-      preStart = ''
-        mkdir -m 0755 -p ${stateDir}/dev/
-        cp ${confFile} ${stateDir}/unbound.conf
-        ${optionalString cfg.enableRootTrustAnchor ''
-          ${cfg.package}/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
+      wantedBy = [ "multi-user.target" "nss-lookup.target" ];
+
+      preStart = lib.mkIf cfg.enableRootTrustAnchor ''
+        ${cfg.package}/bin/unbound-anchor -a ${rootTrustAnchorFile} || echo "Root anchor updated!"
       '';
 
-      serviceConfig = {
-        ExecStart = "${cfg.package}/bin/unbound -d -c ${stateDir}/unbound.conf";
-        ExecStopPost="${pkgs.utillinux}/bin/umount ${stateDir}/dev/random";
+      restartTriggers = [
+        confFile
+      ];
 
-        ProtectSystem = true;
-        ProtectHome = true;
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/unbound -p -d -c /etc/unbound/unbound.conf";
+        ExecReload = "+/run/current-system/sw/bin/kill -HUP $MAINPID";
+
+        NotifyAccess = "main";
+        Type = "notify";
+
+        # FIXME: Which of these do we actualy need, can we drop the chroot flag?
+        AmbientCapabilities = [
+          "CAP_NET_BIND_SERVICE"
+          "CAP_NET_RAW"
+          "CAP_SETGID"
+          "CAP_SETUID"
+          "CAP_SYS_CHROOT"
+          "CAP_SYS_RESOURCE"
+        ];
+
+        User = "unbound";
+        Group = lib.mkIf (cfg.localControlSocketPath != null) (lib.mkDefault "unbound");
+
+        MemoryDenyWriteExecute = true;
+        NoNewPrivileges = true;
         PrivateDevices = true;
-        Restart = "always";
-        RestartSec = "5s";
+        PrivateTmp = true;
+        ProtectHome = true;
+        ProtectControlGroups = true;
+        ProtectKernelModules = true;
+        ProtectSystem = "strict";
+        RuntimeDirectory = "unbound";
+        ConfigurationDirectory = "unbound";
+        StateDirectory = "unbound";
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_NETLINK" "AF_UNIX" ];
+        RestrictRealtime = true;
+        SystemCallArchitectures = "native";
+        SystemCallFilter = [
+          "~@clock"
+          "@cpu-emulation"
+          "@debug"
+          "@keyring"
+          "@module"
+          "mount"
+          "@obsolete"
+          "@resources"
+        ];
+        RestrictNamespaces = true;
+        LockPersonality = true;
+        RestrictSUIDSGID = true;
       };
     };
-
     # If networkmanager is enabled, ask it to interface with unbound.
     networking.networkmanager.dns = "unbound";
-
   };
-
 }
diff --git a/nixpkgs/nixos/modules/services/networking/wakeonlan.nix b/nixpkgs/nixos/modules/services/networking/wakeonlan.nix
index ebfba263cd8f..35ff67937fc7 100644
--- a/nixpkgs/nixos/modules/services/networking/wakeonlan.nix
+++ b/nixpkgs/nixos/modules/services/networking/wakeonlan.nix
@@ -51,6 +51,6 @@ in
 
   ###### implementation
 
-  config.powerManagement.powerDownCommands = lines;
+  config.powerManagement.powerUpCommands = lines;
 
 }
diff --git a/nixpkgs/nixos/modules/services/networking/wasabibackend.nix b/nixpkgs/nixos/modules/services/networking/wasabibackend.nix
index 6eacffe709b0..8482823e197f 100644
--- a/nixpkgs/nixos/modules/services/networking/wasabibackend.nix
+++ b/nixpkgs/nixos/modules/services/networking/wasabibackend.nix
@@ -21,7 +21,7 @@ let
       RegTestBitcoinCoreRpcEndPoint = "${cfg.rpc.ip}:${toString cfg.rpc.port}";
   };
 
-	configFile = pkgs.writeText "wasabibackend.conf" (builtins.toJSON confOptions);
+  configFile = pkgs.writeText "wasabibackend.conf" (builtins.toJSON confOptions);
 
 in {
 
diff --git a/nixpkgs/nixos/modules/services/security/fail2ban.nix b/nixpkgs/nixos/modules/services/security/fail2ban.nix
index 3f84f9c2560c..cf0d72d5c531 100644
--- a/nixpkgs/nixos/modules/services/security/fail2ban.nix
+++ b/nixpkgs/nixos/modules/services/security/fail2ban.nix
@@ -282,12 +282,12 @@ in
     services.fail2ban.jails.DEFAULT = ''
       ${optionalString cfg.bantime-increment.enable ''
         # Bantime incremental
-        bantime.increment    = ${if cfg.bantime-increment.enable then "true" else "false"}
+        bantime.increment    = ${boolToString cfg.bantime-increment.enable}
         bantime.maxtime      = ${cfg.bantime-increment.maxtime}
         bantime.factor       = ${cfg.bantime-increment.factor}
         bantime.formula      = ${cfg.bantime-increment.formula}
         bantime.multipliers  = ${cfg.bantime-increment.multipliers}
-        bantime.overalljails = ${if cfg.bantime-increment.overalljails then "true" else "false"}
+        bantime.overalljails = ${boolToString cfg.bantime-increment.overalljails}
       ''}
       # Miscellaneous options
       ignoreip    = 127.0.0.1/8 ${optionalString config.networking.enableIPv6 "::1"} ${concatStringsSep " " cfg.ignoreIP}
diff --git a/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix b/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix
index 2f9e94bd77ba..486f3ab05386 100644
--- a/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix
+++ b/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix
@@ -448,7 +448,7 @@ in
       default = false;
       description = ''
         In case when running behind a reverse proxy, controls whether headers
-	like <literal>X-Real-Ip</literal> are accepted. Usage behind a reverse
+        like <literal>X-Real-Ip</literal> are accepted. Usage behind a reverse
         proxy will require this flag to be set to avoid logging the reverse
         proxy IP address.
       '';
@@ -524,7 +524,7 @@ in
       type = types.nullOr types.str;
       default = null;
       description = ''
-      	Profile access endpoint.
+        Profile access endpoint.
       '';
     };
 
diff --git a/nixpkgs/nixos/modules/services/security/sshguard.nix b/nixpkgs/nixos/modules/services/security/sshguard.nix
index e7a9cefdef30..72de11a9254c 100644
--- a/nixpkgs/nixos/modules/services/security/sshguard.nix
+++ b/nixpkgs/nixos/modules/services/security/sshguard.nix
@@ -119,15 +119,17 @@ in {
       # firewall rules before sshguard starts.
       preStart = optionalString config.networking.firewall.enable ''
         ${pkgs.ipset}/bin/ipset -quiet create -exist sshguard4 hash:net family inet
-        ${pkgs.ipset}/bin/ipset -quiet create -exist sshguard6 hash:net family inet6
         ${pkgs.iptables}/bin/iptables  -I INPUT -m set --match-set sshguard4 src -j DROP
+      '' + optionalString (config.networking.firewall.enable && config.networking.enableIPv6) ''
+        ${pkgs.ipset}/bin/ipset -quiet create -exist sshguard6 hash:net family inet6
         ${pkgs.iptables}/bin/ip6tables -I INPUT -m set --match-set sshguard6 src -j DROP
       '';
 
       postStop = optionalString config.networking.firewall.enable ''
         ${pkgs.iptables}/bin/iptables  -D INPUT -m set --match-set sshguard4 src -j DROP
-        ${pkgs.iptables}/bin/ip6tables -D INPUT -m set --match-set sshguard6 src -j DROP
         ${pkgs.ipset}/bin/ipset -quiet destroy sshguard4
+      '' + optionalString (config.networking.firewall.enable && config.networking.enableIPv6) ''
+        ${pkgs.iptables}/bin/ip6tables -D INPUT -m set --match-set sshguard6 src -j DROP
         ${pkgs.ipset}/bin/ipset -quiet destroy sshguard6
       '';
 
diff --git a/nixpkgs/nixos/modules/services/security/tor.nix b/nixpkgs/nixos/modules/services/security/tor.nix
index 38dc378887a8..1cceee065b1b 100644
--- a/nixpkgs/nixos/modules/services/security/tor.nix
+++ b/nixpkgs/nixos/modules/services/security/tor.nix
@@ -107,6 +107,9 @@ let
 in
 {
   imports = [
+    (mkRemovedOptionModule [ "services" "tor" "client" "privoxy" "enable" ] ''
+      Use services.privoxy.enable and services.privoxy.enableTor instead.
+    '')
     (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "relay" "port" ])
     (mkRemovedOptionModule [ "services" "tor" "relay" "isBridge" ] "Use services.tor.relay.role instead.")
     (mkRemovedOptionModule [ "services" "tor" "relay" "isExit" ] "Use services.tor.relay.role instead.")
@@ -270,23 +273,6 @@ in
             description = "List of suffixes to use with automapHostsOnResolve";
           };
         };
-
-        privoxy.enable = mkOption {
-          type = types.bool;
-          default = true;
-          description = ''
-            Whether to enable and configure the system Privoxy to use Tor's
-            faster port, suitable for HTTP.
-
-            To have anonymity, protocols need to be scrubbed of identifying
-            information, and this can be accomplished for HTTP by Privoxy.
-
-            Privoxy can also be useful for KDE torification. A good setup would be:
-            setting SOCKS proxy to the default Tor port, providing maximum
-            circuit isolation where possible; and setting HTTP proxy to Privoxy
-            to route HTTP traffic over faster, but less isolated port.
-          '';
-        };
       };
 
       relay = {
@@ -784,16 +770,5 @@ in
       };
 
     environment.systemPackages = [ cfg.package ];
-
-    services.privoxy = mkIf (cfg.client.enable && cfg.client.privoxy.enable) {
-      enable = true;
-      extraConfig = ''
-        forward-socks4a / ${cfg.client.socksListenAddressFaster} .
-        toggle  1
-        enable-remote-toggle 0
-        enable-edit-actions 0
-        enable-remote-http-toggle 0
-      '';
-    };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/security/usbguard.nix b/nixpkgs/nixos/modules/services/security/usbguard.nix
index 16a90da52314..71fd71a2cab2 100644
--- a/nixpkgs/nixos/modules/services/security/usbguard.nix
+++ b/nixpkgs/nixos/modules/services/security/usbguard.nix
@@ -19,13 +19,13 @@ let
     PresentDevicePolicy=${cfg.presentDevicePolicy}
     PresentControllerPolicy=${cfg.presentControllerPolicy}
     InsertedDevicePolicy=${cfg.insertedDevicePolicy}
-    RestoreControllerDeviceState=${if cfg.restoreControllerDeviceState then "true" else "false"}
+    RestoreControllerDeviceState=${boolToString cfg.restoreControllerDeviceState}
     # this does not seem useful for endusers to change
     DeviceManagerBackend=uevent
     IPCAllowedUsers=${concatStringsSep " " cfg.IPCAllowedUsers}
     IPCAllowedGroups=${concatStringsSep " " cfg.IPCAllowedGroups}
     IPCAccessControlFiles=/var/lib/usbguard/IPCAccessControl.d/
-    DeviceRulesWithPort=${if cfg.deviceRulesWithPort then "true" else "false"}
+    DeviceRulesWithPort=${boolToString cfg.deviceRulesWithPort}
     # HACK: that way audit logs still land in the journal
     AuditFilePath=/dev/null
   '';
diff --git a/nixpkgs/nixos/modules/services/security/vault.nix b/nixpkgs/nixos/modules/services/security/vault.nix
index 6a8a3a93327e..64622454b9de 100644
--- a/nixpkgs/nixos/modules/services/security/vault.nix
+++ b/nixpkgs/nixos/modules/services/security/vault.nix
@@ -131,6 +131,8 @@ in
 
       restartIfChanged = false; # do not restart on "nixos-rebuild switch". It would seal the storage and disrupt the clients.
 
+      startLimitIntervalSec = 60;
+      startLimitBurst = 3;
       serviceConfig = {
         User = "vault";
         Group = "vault";
@@ -145,8 +147,6 @@ in
         KillSignal = "SIGINT";
         TimeoutStopSec = "30s";
         Restart = "on-failure";
-        StartLimitInterval = "60s";
-        StartLimitBurst = 3;
       };
 
       unitConfig.RequiresMountsFor = optional (cfg.storagePath != null) cfg.storagePath;
diff --git a/nixpkgs/nixos/modules/services/system/cloud-init.nix b/nixpkgs/nixos/modules/services/system/cloud-init.nix
index 15fe822aec67..3518e0ee9dca 100644
--- a/nixpkgs/nixos/modules/services/system/cloud-init.nix
+++ b/nixpkgs/nixos/modules/services/system/cloud-init.nix
@@ -9,7 +9,7 @@ let cfg = config.services.cloud-init;
       nettools
       openssh
       shadow
-      utillinux
+      util-linux
     ] ++ optional cfg.btrfs.enable btrfs-progs
       ++ optional cfg.ext4.enable e2fsprogs
     ;
diff --git a/nixpkgs/nixos/modules/services/system/dbus.nix b/nixpkgs/nixos/modules/services/system/dbus.nix
index 4a60fec1ca80..d4cacb85694b 100644
--- a/nixpkgs/nixos/modules/services/system/dbus.nix
+++ b/nixpkgs/nixos/modules/services/system/dbus.nix
@@ -1,6 +1,6 @@
 # D-Bus configuration and system bus daemon.
 
-{ config, lib, pkgs, ... }:
+{ config, lib, options, pkgs, ... }:
 
 with lib;
 
@@ -11,6 +11,7 @@ let
   homeDir = "/run/dbus";
 
   configDir = pkgs.makeDBusConf {
+    inherit (cfg) apparmor;
     suidHelper = "${config.security.wrapperDir}/dbus-daemon-launch-helper";
     serviceDirectories = cfg.packages;
   };
@@ -18,7 +19,6 @@ let
 in
 
 {
-
   ###### interface
 
   options = {
@@ -52,11 +52,26 @@ in
         '';
       };
 
+      apparmor = mkOption {
+        type = types.enum [ "enabled" "disabled" "required" ];
+        description = ''
+          AppArmor mode for dbus.
+
+          <literal>enabled</literal> enables mediation when it's
+          supported in the kernel, <literal>disabled</literal>
+          always disables AppArmor even with kernel support, and
+          <literal>required</literal> fails when AppArmor was not found
+          in the kernel.
+        '';
+        default = "disabled";
+      };
+
       socketActivated = mkOption {
-        type = types.bool;
-        default = false;
+        type = types.nullOr types.bool;
+        default = null;
+        visible = false;
         description = ''
-          Make the user instance socket activated.
+          Removed option, do not use.
         '';
       };
     };
@@ -65,6 +80,14 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
+    warnings = optional (cfg.socketActivated != null) (
+      let
+        files = showFiles options.services.dbus.socketActivated.files;
+      in
+        "The option 'services.dbus.socketActivated' in ${files} no longer has"
+        + " any effect and can be safely removed: the user D-Bus session is"
+        + " now always socket activated."
+    );
 
     environment.systemPackages = [ pkgs.dbus.daemon pkgs.dbus ];
 
@@ -108,7 +131,7 @@ in
         reloadIfChanged = true;
         restartTriggers = [ configDir ];
       };
-      sockets.dbus.wantedBy = mkIf cfg.socketActivated [ "sockets.target" ];
+      sockets.dbus.wantedBy = [ "sockets.target" ];
     };
 
     environment.pathsToLink = [ "/etc/dbus-1" "/share/dbus-1" ];
diff --git a/nixpkgs/nixos/modules/services/torrent/transmission.nix b/nixpkgs/nixos/modules/services/torrent/transmission.nix
index 014a22bb5a8d..7bec073e26f7 100644
--- a/nixpkgs/nixos/modules/services/torrent/transmission.nix
+++ b/nixpkgs/nixos/modules/services/torrent/transmission.nix
@@ -197,7 +197,7 @@ in
           install -D -m 600 -o '${cfg.user}' -g '${cfg.group}' /dev/stdin \
            '${cfg.home}/${settingsDir}/settings.json'
         '')];
-        ExecStart="${pkgs.transmission}/bin/transmission-daemon -f";
+        ExecStart="${pkgs.transmission}/bin/transmission-daemon -f -g ${cfg.home}/${settingsDir}";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         User = cfg.user;
         Group = cfg.group;
@@ -236,6 +236,7 @@ in
           # an AppArmor profile is provided to get a confinement based upon paths and rights.
           builtins.storeDir
           "/etc"
+          "/run"
           ] ++
           optional (cfg.settings.script-torrent-done-enabled &&
                     cfg.settings.script-torrent-done-filename != "")
@@ -396,9 +397,9 @@ in
           mr ${getLib pkgs.openssl}/lib/libcrypto*.so*,
           mr ${getLib pkgs.openssl}/lib/libssl*.so*,
           mr ${getLib pkgs.systemd}/lib/libsystemd*.so*,
-          mr ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so*,
-          mr ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so*,
-          mr ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so*,
+          mr ${getLib pkgs.util-linuxMinimal.out}/lib/libblkid.so*,
+          mr ${getLib pkgs.util-linuxMinimal.out}/lib/libmount.so*,
+          mr ${getLib pkgs.util-linuxMinimal.out}/lib/libuuid.so*,
           mr ${getLib pkgs.xz}/lib/liblzma*.so*,
           mr ${getLib pkgs.zlib}/lib/libz*.so*,
 
@@ -408,6 +409,7 @@ in
           #r @{PROC}/@{pid}/environ,
           r @{PROC}/@{pid}/mounts,
           rwk /tmp/tr_session_id_*,
+          r /run/systemd/resolve/stub-resolv.conf,
 
           r ${pkgs.openssl.out}/etc/**,
           r ${config.systemd.services.transmission.environment.CURL_CA_BUNDLE},
diff --git a/nixpkgs/nixos/modules/services/ttys/agetty.nix b/nixpkgs/nixos/modules/services/ttys/agetty.nix
index ef5908eeb899..5d8b21cea3f1 100644
--- a/nixpkgs/nixos/modules/services/ttys/agetty.nix
+++ b/nixpkgs/nixos/modules/services/ttys/agetty.nix
@@ -14,7 +14,7 @@ let
   ];
 
   gettyCmd = extraArgs:
-    "@${pkgs.utillinux}/sbin/agetty agetty ${escapeShellArgs loginArgs} "
+    "@${pkgs.util-linux}/sbin/agetty agetty ${escapeShellArgs loginArgs} "
       + extraArgs;
 
 in
diff --git a/nixpkgs/nixos/modules/services/video/epgstation/generate b/nixpkgs/nixos/modules/services/video/epgstation/generate
deleted file mode 100755
index 2940768b6d2c..000000000000
--- a/nixpkgs/nixos/modules/services/video/epgstation/generate
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env -S nix-build --no-out-link
-
-# Script to generate default streaming configurations for EPGStation. There's
-# no need to run this script directly since generate.sh in the EPGStation
-# package directory would run this script for you.
-#
-# Usage: ./generate | xargs cat > streaming.json
-
-{ pkgs ? (import ../../../../.. {}) }:
-
-let
-  sampleConfigPath = "${pkgs.epgstation.src}/config/config.sample.json";
-  sampleConfig = builtins.fromJSON (builtins.readFile sampleConfigPath);
-  streamingConfig = {
-    inherit (sampleConfig)
-      mpegTsStreaming
-      mpegTsViewer
-      liveHLS
-      liveMP4
-      liveWebM
-      recordedDownloader
-      recordedStreaming
-      recordedViewer
-      recordedHLS;
-  };
-in
-pkgs.runCommand "streaming.json" { nativeBuildInputs = [ pkgs.jq ]; } ''
-  jq . <<<'${builtins.toJSON streamingConfig}' > $out
-''
-
-# vim:set ft=nix:
diff --git a/nixpkgs/nixos/modules/services/video/epgstation/streaming.json b/nixpkgs/nixos/modules/services/video/epgstation/streaming.json
index 37957f6cb6a2..8eb99cf85584 100644
--- a/nixpkgs/nixos/modules/services/video/epgstation/streaming.json
+++ b/nixpkgs/nixos/modules/services/video/epgstation/streaming.json
@@ -1,119 +1,119 @@
 {
   "liveHLS": [
     {
-      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%",
-      "name": "720p"
+      "name": "720p",
+      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%"
     },
     {
-      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%",
-      "name": "480p"
+      "name": "480p",
+      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%"
     },
     {
-      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 48k -ac 2 -c:v libx264 -vf yadif,scale=-2:180 -b:v 100k -preset veryfast -maxrate 110k -bufsize 1000k -flags +loop-global_header %OUTPUT%",
-      "name": "180p"
+      "name": "180p",
+      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 48k -ac 2 -c:v libx264 -vf yadif,scale=-2:180 -b:v 100k -preset veryfast -maxrate 110k -bufsize 1000k -flags +loop-global_header %OUTPUT%"
     }
   ],
   "liveMP4": [
     {
-      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
-      "name": "720p"
+      "name": "720p",
+      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
     },
     {
-      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
-      "name": "480p"
+      "name": "480p",
+      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
     }
   ],
   "liveWebM": [
     {
-      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
-      "name": "720p"
+      "name": "720p",
+      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
     },
     {
-      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
-      "name": "480p"
+      "name": "480p",
+      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
     }
   ],
   "mpegTsStreaming": [
     {
-      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1",
-      "name": "720p"
+      "name": "720p",
+      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1"
     },
     {
-      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1",
-      "name": "480p"
+      "name": "480p",
+      "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1"
     },
     {
       "name": "Original"
     }
   ],
   "mpegTsViewer": {
-    "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end",
-    "ios": "vlc-x-callback://x-callback-url/stream?url=http://ADDRESS"
+    "ios": "vlc-x-callback://x-callback-url/stream?url=http://ADDRESS",
+    "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end"
   },
   "recordedDownloader": {
-    "android": "intent://ADDRESS#Intent;package=com.dv.adm;type=video;scheme=http;end",
-    "ios": "vlc-x-callback://x-callback-url/download?url=http://ADDRESS&filename=FILENAME"
+    "ios": "vlc-x-callback://x-callback-url/download?url=http://ADDRESS&filename=FILENAME",
+    "android": "intent://ADDRESS#Intent;package=com.dv.adm;type=video;scheme=http;end"
   },
-  "recordedHLS": [
-    {
-      "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%",
-      "name": "720p"
-    },
-    {
-      "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%",
-      "name": "480p"
-    },
-    {
-      "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_type fmp4 -hls_fmp4_init_filename stream%streamNum%-init.mp4 -hls_segment_filename stream%streamNum%-%09d.m4s -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx265 -vf yadif,scale=-2:480 -b:v 350k -preset veryfast -tag:v hvc1 %OUTPUT%",
-      "name": "480p(h265)"
-    }
-  ],
   "recordedStreaming": {
-    "mp4": [
+    "webm": [
       {
-        "ab": "192k",
-        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
         "name": "720p",
-        "vb": "3000k"
+        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
+        "vb": "3000k",
+        "ab": "192k"
       },
       {
-        "ab": "128k",
-        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
         "name": "360p",
-        "vb": "1500k"
+        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
+        "vb": "1500k",
+        "ab": "128k"
       }
     ],
-    "mpegTs": [
+    "mp4": [
       {
-        "ab": "192k",
-        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1",
-        "name": "720p (H.264)",
-        "vb": "3000k"
+        "name": "720p",
+        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
+        "vb": "3000k",
+        "ab": "192k"
       },
       {
-        "ab": "128k",
-        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1",
-        "name": "360p (H.264)",
-        "vb": "1500k"
+        "name": "360p",
+        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
+        "vb": "1500k",
+        "ab": "128k"
       }
     ],
-    "webm": [
+    "mpegTs": [
       {
-        "ab": "192k",
-        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
-        "name": "720p",
-        "vb": "3000k"
+        "name": "720p (H.264)",
+        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1",
+        "vb": "3000k",
+        "ab": "192k"
       },
       {
-        "ab": "128k",
-        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
-        "name": "360p",
-        "vb": "1500k"
+        "name": "360p (H.264)",
+        "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1",
+        "vb": "1500k",
+        "ab": "128k"
       }
     ]
   },
+  "recordedHLS": [
+    {
+      "name": "720p",
+      "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%"
+    },
+    {
+      "name": "480p",
+      "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%"
+    },
+    {
+      "name": "480p(h265)",
+      "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_type fmp4 -hls_fmp4_init_filename stream%streamNum%-init.mp4 -hls_segment_filename stream%streamNum%-%09d.m4s -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx265 -vf yadif,scale=-2:480 -b:v 350k -preset veryfast -tag:v hvc1 %OUTPUT%"
+    }
+  ],
   "recordedViewer": {
-    "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end",
-    "ios": "infuse://x-callback-url/play?url=http://ADDRESS"
+    "ios": "infuse://x-callback-url/play?url=http://ADDRESS",
+    "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end"
   }
 }
diff --git a/nixpkgs/nixos/modules/services/web-apps/engelsystem.nix b/nixpkgs/nixos/modules/services/web-apps/engelsystem.nix
index 899582a20304..2e755ae9d523 100644
--- a/nixpkgs/nixos/modules/services/web-apps/engelsystem.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/engelsystem.nix
@@ -10,7 +10,7 @@ in {
         default = false;
         example = true;
         description = ''
-          Whether to enable engelsystem, an online tool for coordinating helpers
+          Whether to enable engelsystem, an online tool for coordinating volunteers
           and shifts on large events.
         '';
         type = lib.types.bool;
diff --git a/nixpkgs/nixos/modules/services/web-apps/frab.nix b/nixpkgs/nixos/modules/services/web-apps/frab.nix
deleted file mode 100644
index 1b5890d6b0c7..000000000000
--- a/nixpkgs/nixos/modules/services/web-apps/frab.nix
+++ /dev/null
@@ -1,222 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.services.frab;
-
-  package = pkgs.frab;
-
-  databaseConfig = builtins.toJSON { production = cfg.database; };
-
-  frabEnv = {
-    RAILS_ENV = "production";
-    RACK_ENV = "production";
-    SECRET_KEY_BASE = cfg.secretKeyBase;
-    FRAB_HOST = cfg.host;
-    FRAB_PROTOCOL = cfg.protocol;
-    FROM_EMAIL = cfg.fromEmail;
-    RAILS_SERVE_STATIC_FILES = "1";
-  } // cfg.extraEnvironment;
-
-  frab-rake = pkgs.stdenv.mkDerivation {
-    name = "frab-rake";
-    buildInputs = [ package.env pkgs.makeWrapper ];
-    phases = "installPhase fixupPhase";
-    installPhase = ''
-      mkdir -p $out/bin
-      makeWrapper ${package.env}/bin/bundle $out/bin/frab-bundle \
-          ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") frabEnv)} \
-          --set PATH '${lib.makeBinPath (with pkgs; [ nodejs file imagemagick ])}:$PATH' \
-          --set RAKEOPT '-f ${package}/share/frab/Rakefile' \
-          --run 'cd ${package}/share/frab'
-      makeWrapper $out/bin/frab-bundle $out/bin/frab-rake \
-          --add-flags "exec rake"
-     '';
-  };
-
-in
-
-{
-  options = {
-    services.frab = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Enable the frab service.
-        '';
-      };
-
-      host = mkOption {
-        type = types.str;
-        example = "frab.example.com";
-        description = ''
-          Hostname under which this frab instance can be reached.
-        '';
-      };
-
-      protocol = mkOption {
-        type = types.str;
-        default = "https";
-        example = "http";
-        description = ''
-          Either http or https, depending on how your Frab instance
-          will be exposed to the public.
-        '';
-      };
-
-      fromEmail = mkOption {
-        type = types.str;
-        default = "frab@localhost";
-        description = ''
-          Email address used by frab.
-        '';
-      };
-
-      listenAddress = mkOption {
-        type = types.str;
-        default = "localhost";
-        description = ''
-          Address or hostname frab should listen on.
-        '';
-      };
-
-      listenPort = mkOption {
-        type = types.int;
-        default = 3000;
-        description = ''
-          Port frab should listen on.
-        '';
-      };
-
-      statePath = mkOption {
-        type = types.str;
-        default = "/var/lib/frab";
-        description = ''
-          Directory where frab keeps its state.
-        '';
-      };
-
-      user = mkOption {
-        type = types.str;
-        default = "frab";
-        description = ''
-          User to run frab.
-        '';
-      };
-
-      group = mkOption {
-        type = types.str;
-        default = "frab";
-        description = ''
-          Group to run frab.
-        '';
-      };
-
-      secretKeyBase = mkOption {
-        type = types.str;
-        description = ''
-          Your secret key is used for verifying the integrity of signed cookies.
-          If you change this key, all old signed cookies will become invalid!
-
-          Make sure the secret is at least 30 characters and all random,
-          no regular words or you'll be exposed to dictionary attacks.
-        '';
-      };
-
-      database = mkOption {
-        type = types.attrs;
-        default = {
-          adapter = "sqlite3";
-          database = "/var/lib/frab/db.sqlite3";
-          pool = 5;
-          timeout = 5000;
-        };
-        example = {
-          adapter = "postgresql";
-          database = "frab";
-          host = "localhost";
-          username = "frabuser";
-          password = "supersecret";
-          encoding = "utf8";
-          pool = 5;
-        };
-        description = ''
-          Rails database configuration for Frab as Nix attribute set.
-        '';
-      };
-
-      extraEnvironment = mkOption {
-        type = types.attrs;
-        default = {};
-        example = {
-          FRAB_CURRENCY_UNIT = "€";
-          FRAB_CURRENCY_FORMAT = "%n%u";
-          EXCEPTION_EMAIL = "frab-owner@example.com";
-          SMTP_ADDRESS = "localhost";
-          SMTP_PORT = "587";
-          SMTP_DOMAIN = "localdomain";
-          SMTP_USER_NAME = "root";
-          SMTP_PASSWORD = "toor";
-          SMTP_AUTHENTICATION = "1";
-          SMTP_NOTLS = "1";
-        };
-        description = ''
-          Additional environment variables to set for frab for further
-          configuration. See the frab documentation for more information.
-        '';
-      };
-    };
-  };
-
-  config = mkIf cfg.enable {
-    environment.systemPackages = [ frab-rake ];
-
-    users.users.${cfg.user} =
-      { group = cfg.group;
-        home = "${cfg.statePath}";
-        isSystemUser = true;
-      };
-
-    users.groups.${cfg.group} = { };
-
-    systemd.tmpfiles.rules = [
-      "d '${cfg.statePath}/system/attachments' - ${cfg.user} ${cfg.group} - -"
-    ];
-
-    systemd.services.frab = {
-      after = [ "network.target" "gitlab.service" ];
-      wantedBy = [ "multi-user.target" ];
-      environment = frabEnv;
-
-      preStart = ''
-        ln -sf ${pkgs.writeText "frab-database.yml" databaseConfig} /run/frab/database.yml
-        ln -sf ${cfg.statePath}/system /run/frab/system
-
-        if ! test -e "${cfg.statePath}/db-setup-done"; then
-          ${frab-rake}/bin/frab-rake db:setup
-          touch ${cfg.statePath}/db-setup-done
-        else
-          ${frab-rake}/bin/frab-rake db:migrate
-        fi
-      '';
-
-      serviceConfig = {
-        PrivateTmp = true;
-        PrivateDevices = true;
-        Type = "simple";
-        User = cfg.user;
-        Group = cfg.group;
-        TimeoutSec = "300s";
-        Restart = "on-failure";
-        RestartSec = "10s";
-        RuntimeDirectory = "frab";
-        WorkingDirectory = "${package}/share/frab";
-        ExecStart = "${frab-rake}/bin/frab-bundle exec rails server " +
-          "--binding=${cfg.listenAddress} --port=${toString cfg.listenPort}";
-      };
-    };
-
-  };
-}
diff --git a/nixpkgs/nixos/modules/services/web-apps/gerrit.nix b/nixpkgs/nixos/modules/services/web-apps/gerrit.nix
index 657b1a4fc5ba..864587aea565 100644
--- a/nixpkgs/nixos/modules/services/web-apps/gerrit.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/gerrit.nix
@@ -143,7 +143,7 @@ in
           Set a UUID that uniquely identifies the server.
 
           This can be generated with
-          <literal>nix-shell -p utillinux --run uuidgen</literal>.
+          <literal>nix-shell -p util-linux --run uuidgen</literal>.
         '';
       };
     };
diff --git a/nixpkgs/nixos/modules/services/web-apps/grocy.nix b/nixpkgs/nixos/modules/services/web-apps/grocy.nix
index 568bdfd0c429..be2de638dd96 100644
--- a/nixpkgs/nixos/modules/services/web-apps/grocy.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/grocy.nix
@@ -115,9 +115,9 @@ in {
       user = "grocy";
       group = "nginx";
 
-      # PHP 7.3 is the only version which is supported/tested by upstream:
-      # https://github.com/grocy/grocy/blob/v2.6.0/README.md#how-to-install
-      phpPackage = pkgs.php73;
+      # PHP 7.4 is the only version which is supported/tested by upstream:
+      # https://github.com/grocy/grocy/blob/v3.0.0/README.md#how-to-install
+      phpPackage = pkgs.php74;
 
       inherit (cfg.phpfpm) settings;
 
diff --git a/nixpkgs/nixos/modules/services/web-apps/codimd.nix b/nixpkgs/nixos/modules/services/web-apps/hedgedoc.nix
index c787c36b877c..3f646d7db0cd 100644
--- a/nixpkgs/nixos/modules/services/web-apps/codimd.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/hedgedoc.nix
@@ -3,31 +3,41 @@
 with lib;
 
 let
-  cfg = config.services.codimd;
+  cfg = config.services.hedgedoc;
+
+  name = if versionAtLeast config.system.stateVersion "21.03"
+    then "hedgedoc"
+    else "codimd";
 
   prettyJSON = conf:
-    pkgs.runCommand "codimd-config.json" { preferLocalBuild = true; } ''
-      echo '${builtins.toJSON conf}' | ${pkgs.jq}/bin/jq \
+    pkgs.runCommandLocal "hedgedoc-config.json" {
+      nativeBuildInputs = [ pkgs.jq ];
+    } ''
+      echo '${builtins.toJSON conf}' | jq \
         '{production:del(.[]|nulls)|del(.[][]?|nulls)}' > $out
     '';
 in
 {
-  options.services.codimd = {
-    enable = mkEnableOption "the CodiMD Markdown Editor";
+  imports = [
+    (mkRenamedOptionModule [ "services" "codimd" ] [ "services" "hedgedoc" ])
+  ];
+
+  options.services.hedgedoc = {
+    enable = mkEnableOption "the HedgeDoc Markdown Editor";
 
     groups = mkOption {
       type = types.listOf types.str;
       default = [];
       description = ''
-        Groups to which the codimd user should be added.
+        Groups to which the user ${name} should be added.
       '';
     };
 
     workDir = mkOption {
       type = types.path;
-      default = "/var/lib/codimd";
+      default = "/var/lib/${name}";
       description = ''
-        Working directory for the CodiMD service.
+        Working directory for the HedgeDoc service.
       '';
     };
 
@@ -36,17 +46,17 @@ in
       domain = mkOption {
         type = types.nullOr types.str;
         default = null;
-        example = "codimd.org";
+        example = "hedgedoc.org";
         description = ''
-          Domain name for the CodiMD instance.
+          Domain name for the HedgeDoc instance.
         '';
       };
       urlPath = mkOption {
         type = types.nullOr types.str;
         default = null;
-        example = "/url/path/to/codimd";
+        example = "/url/path/to/hedgedoc";
         description = ''
-          Path under which CodiMD is accessible.
+          Path under which HedgeDoc is accessible.
         '';
       };
       host = mkOption {
@@ -67,7 +77,7 @@ in
       path = mkOption {
         type = types.nullOr types.str;
         default = null;
-        example = "/run/codimd.sock";
+        example = "/run/hedgedoc.sock";
         description = ''
           Specify where a UNIX domain socket should be placed.
         '';
@@ -75,7 +85,7 @@ in
       allowOrigin = mkOption {
         type = types.listOf types.str;
         default = [];
-        example = [ "localhost" "codimd.org" ];
+        example = [ "localhost" "hedgedoc.org" ];
         description = ''
           List of domains to whitelist.
         '';
@@ -199,7 +209,7 @@ in
         '';
         description = ''
           Specify which database to use.
-          CodiMD supports mysql, postgres, sqlite and mssql.
+          HedgeDoc supports mysql, postgres, sqlite and mssql.
           See <link xlink:href="https://sequelize.readthedocs.io/en/v3/">
           https://sequelize.readthedocs.io/en/v3/</link> for more information.
           Note: This option overrides <option>db</option>.
@@ -211,12 +221,12 @@ in
         example = literalExample ''
           {
             dialect = "sqlite";
-            storage = "/var/lib/codimd/db.codimd.sqlite";
+            storage = "/var/lib/${name}/db.${name}.sqlite";
           }
         '';
         description = ''
           Specify the configuration for sequelize.
-          CodiMD supports mysql, postgres, sqlite and mssql.
+          HedgeDoc supports mysql, postgres, sqlite and mssql.
           See <link xlink:href="https://sequelize.readthedocs.io/en/v3/">
           https://sequelize.readthedocs.io/en/v3/</link> for more information.
           Note: This option overrides <option>db</option>.
@@ -225,7 +235,7 @@ in
       sslKeyPath= mkOption {
         type = types.nullOr types.str;
         default = null;
-        example = "/var/lib/codimd/codimd.key";
+        example = "/var/lib/hedgedoc/hedgedoc.key";
         description = ''
           Path to the SSL key. Needed when <option>useSSL</option> is enabled.
         '';
@@ -233,7 +243,7 @@ in
       sslCertPath = mkOption {
         type = types.nullOr types.str;
         default = null;
-        example = "/var/lib/codimd/codimd.crt";
+        example = "/var/lib/hedgedoc/hedgedoc.crt";
         description = ''
           Path to the SSL cert. Needed when <option>useSSL</option> is enabled.
         '';
@@ -241,7 +251,7 @@ in
       sslCAPath = mkOption {
         type = types.listOf types.str;
         default = [];
-        example = [ "/var/lib/codimd/ca.crt" ];
+        example = [ "/var/lib/hedgedoc/ca.crt" ];
         description = ''
           SSL ca chain. Needed when <option>useSSL</option> is enabled.
         '';
@@ -249,7 +259,7 @@ in
       dhParamPath = mkOption {
         type = types.nullOr types.str;
         default = null;
-        example = "/var/lib/codimd/dhparam.pem";
+        example = "/var/lib/hedgedoc/dhparam.pem";
         description = ''
           Path to the SSL dh params. Needed when <option>useSSL</option> is enabled.
         '';
@@ -258,10 +268,10 @@ in
         type = types.str;
         default = "/tmp";
         description = ''
-          Path to the temp directory CodiMD should use.
+          Path to the temp directory HedgeDoc should use.
           Note that <option>serviceConfig.PrivateTmp</option> is enabled for
-          the CodiMD systemd service by default.
-          (Non-canonical paths are relative to CodiMD's base directory)
+          the HedgeDoc systemd service by default.
+          (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
       };
       defaultNotePath = mkOption {
@@ -269,7 +279,7 @@ in
         default = "./public/default.md";
         description = ''
           Path to the default Note file.
-          (Non-canonical paths are relative to CodiMD's base directory)
+          (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
       };
       docsPath = mkOption {
@@ -277,7 +287,7 @@ in
         default = "./public/docs";
         description = ''
           Path to the docs directory.
-          (Non-canonical paths are relative to CodiMD's base directory)
+          (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
       };
       indexPath = mkOption {
@@ -285,7 +295,7 @@ in
         default = "./public/views/index.ejs";
         description = ''
           Path to the index template file.
-          (Non-canonical paths are relative to CodiMD's base directory)
+          (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
       };
       hackmdPath = mkOption {
@@ -293,7 +303,7 @@ in
         default = "./public/views/hackmd.ejs";
         description = ''
           Path to the hackmd template file.
-          (Non-canonical paths are relative to CodiMD's base directory)
+          (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
       };
       errorPath = mkOption {
@@ -302,7 +312,7 @@ in
         defaultText = "./public/views/error.ejs";
         description = ''
           Path to the error template file.
-          (Non-canonical paths are relative to CodiMD's base directory)
+          (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
       };
       prettyPath = mkOption {
@@ -311,7 +321,7 @@ in
         defaultText = "./public/views/pretty.ejs";
         description = ''
           Path to the pretty template file.
-          (Non-canonical paths are relative to CodiMD's base directory)
+          (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
       };
       slidePath = mkOption {
@@ -320,13 +330,13 @@ in
         defaultText = "./public/views/slide.hbs";
         description = ''
           Path to the slide template file.
-          (Non-canonical paths are relative to CodiMD's base directory)
+          (Non-canonical paths are relative to HedgeDoc's base directory)
         '';
       };
       uploadsPath = mkOption {
         type = types.str;
         default = "${cfg.workDir}/uploads";
-        defaultText = "/var/lib/codimd/uploads";
+        defaultText = "/var/lib/${name}/uploads";
         description = ''
           Path under which uploaded files are saved.
         '';
@@ -764,7 +774,7 @@ in
               type = types.str;
               default = "";
               description = ''
-                LDAP field which is used as the username on CodiMD.
+                LDAP field which is used as the username on HedgeDoc.
                 By default <option>useridField</option> is used.
               '';
             };
@@ -772,7 +782,7 @@ in
               type = types.str;
               example = "uid";
               description = ''
-                LDAP field which is a unique identifier for users on CodiMD.
+                LDAP field which is a unique identifier for users on HedgeDoc.
               '';
             };
             tlsca = mkOption {
@@ -838,7 +848,7 @@ in
             requiredGroups = mkOption {
               type = types.listOf types.str;
               default = [];
-              example = [ "Hackmd-users" "Codimd-users" ];
+              example = [ "Hedgedoc-Users" ];
               description = ''
                 Required group names.
               '';
@@ -878,11 +888,10 @@ in
       };
     };
 
-
     environmentFile = mkOption {
       type = with types; nullOr path;
       default = null;
-      example = "/var/lib/codimd/codimd.env";
+      example = "/var/lib/hedgedoc/hedgedoc.env";
       description = ''
         Environment file as defined in <citerefentry>
         <refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum>
@@ -893,9 +902,9 @@ in
         setting these variables accordingly in the environment file.
 
         <programlisting>
-          # snippet of CodiMD-related config
-          services.codimd.configuration.dbURL = "postgres://codimd:\''${DB_PASSWORD}@db-host:5432/codimddb";
-          services.codimd.configuration.minio.secretKey = "$MINIO_SECRET_KEY";
+          # snippet of HedgeDoc-related config
+          services.hedgedoc.configuration.dbURL = "postgres://hedgedoc:\''${DB_PASSWORD}@db-host:5432/hedgedocdb";
+          services.hedgedoc.configuration.minio.secretKey = "$MINIO_SECRET_KEY";
         </programlisting>
 
         <programlisting>
@@ -905,7 +914,15 @@ in
         </programlisting>
 
         Note that this file needs to be available on the host on which
-        <literal>CodiMD</literal> is running.
+        <literal>HedgeDoc</literal> is running.
+      '';
+    };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.hedgedoc;
+      description = ''
+        Package that provides HedgeDoc.
       '';
     };
   };
@@ -915,20 +932,20 @@ in
       { assertion = cfg.configuration.db == {} -> (
           cfg.configuration.dbURL != "" && cfg.configuration.dbURL != null
         );
-        message = "Database configuration for CodiMD missing."; }
+        message = "Database configuration for HedgeDoc missing."; }
     ];
-    users.groups.codimd = {};
-    users.users.codimd = {
-      description = "CodiMD service user";
-      group = "codimd";
+    users.groups.${name} = {};
+    users.users.${name} = {
+      description = "HedgeDoc service user";
+      group = name;
       extraGroups = cfg.groups;
       home = cfg.workDir;
       createHome = true;
       isSystemUser = true;
     };
 
-    systemd.services.codimd = {
-      description = "CodiMD Service";
+    systemd.services.hedgedoc = {
+      description = "HedgeDoc Service";
       wantedBy = [ "multi-user.target" ];
       after = [ "networking.target" ];
       preStart = ''
@@ -938,14 +955,14 @@ in
       '';
       serviceConfig = {
         WorkingDirectory = cfg.workDir;
-        ExecStart = "${pkgs.codimd}/bin/codimd";
+        ExecStart = "${cfg.package}/bin/hedgedoc";
         EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ];
         Environment = [
           "CMD_CONFIG_FILE=${cfg.workDir}/config.json"
           "NODE_ENV=production"
         ];
         Restart = "always";
-        User = "codimd";
+        User = name;
         PrivateTmp = true;
       };
     };
diff --git a/nixpkgs/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix b/nixpkgs/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
index d9ad7e9e3d39..eea49bda283b 100644
--- a/nixpkgs/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix
@@ -167,8 +167,8 @@ in {
     services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
       ${poolName} = {
         user = "icingaweb2";
+        phpPackage = pkgs.php.withExtensions ({ enabled, all }: [ all.imagick ] ++ enabled);
         phpOptions = ''
-          extension = ${pkgs.phpPackages.imagick}/lib/php/extensions/imagick.so
           date.timezone = "${cfg.timezone}"
         '';
         settings = mapAttrs (name: mkDefault) {
diff --git a/nixpkgs/nixos/modules/services/web-apps/keycloak.nix b/nixpkgs/nixos/modules/services/web-apps/keycloak.nix
new file mode 100644
index 000000000000..bbb0c8d04831
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/keycloak.nix
@@ -0,0 +1,692 @@
+{ config, pkgs, lib, ... }:
+
+let
+  cfg = config.services.keycloak;
+in
+{
+  options.services.keycloak = {
+
+    enable = lib.mkOption {
+      type = lib.types.bool;
+      default = false;
+      example = true;
+      description = ''
+        Whether to enable the Keycloak identity and access management
+        server.
+      '';
+    };
+
+    bindAddress = lib.mkOption {
+      type = lib.types.str;
+      default = "\${jboss.bind.address:0.0.0.0}";
+      example = "127.0.0.1";
+      description = ''
+        On which address Keycloak should accept new connections.
+
+        A special syntax can be used to allow command line Java system
+        properties to override the value: ''${property.name:value}
+      '';
+    };
+
+    httpPort = lib.mkOption {
+      type = lib.types.str;
+      default = "\${jboss.http.port:80}";
+      example = "8080";
+      description = ''
+        On which port Keycloak should listen for new HTTP connections.
+
+        A special syntax can be used to allow command line Java system
+        properties to override the value: ''${property.name:value}
+      '';
+    };
+
+    httpsPort = lib.mkOption {
+      type = lib.types.str;
+      default = "\${jboss.https.port:443}";
+      example = "8443";
+      description = ''
+        On which port Keycloak should listen for new HTTPS connections.
+
+        A special syntax can be used to allow command line Java system
+        properties to override the value: ''${property.name:value}
+      '';
+    };
+
+    frontendUrl = lib.mkOption {
+      type = lib.types.str;
+      example = "keycloak.example.com/auth";
+      description = ''
+        The public URL used as base for all frontend requests. Should
+        normally include a trailing <literal>/auth</literal>.
+
+        See <link xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">the
+        Hostname section of the Keycloak server installation
+        manual</link> for more information.
+      '';
+    };
+
+    forceBackendUrlToFrontendUrl = lib.mkOption {
+      type = lib.types.bool;
+      default = false;
+      example = true;
+      description = ''
+        Whether Keycloak should force all requests to go through the
+        frontend URL configured in <xref
+        linkend="opt-services.keycloak.frontendUrl" />. By default,
+        Keycloak allows backend requests to instead use its local
+        hostname or IP address and may also advertise it to clients
+        through its OpenID Connect Discovery endpoint.
+
+        See <link
+        xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">the
+        Hostname section of the Keycloak server installation
+        manual</link> for more information.
+      '';
+    };
+
+    certificatePrivateKeyBundle = lib.mkOption {
+      type = lib.types.nullOr lib.types.path;
+      default = null;
+      example = "/run/keys/ssl_cert";
+      description = ''
+        The path to a PEM formatted bundle of the private key and
+        certificate to use for TLS connections.
+
+        This should be a string, not a Nix path, since Nix paths are
+        copied into the world-readable Nix store.
+      '';
+    };
+
+    databaseType = lib.mkOption {
+      type = lib.types.enum [ "mysql" "postgresql" ];
+      default = "postgresql";
+      example = "mysql";
+      description = ''
+        The type of database Keycloak should connect to.
+      '';
+    };
+
+    databaseHost = lib.mkOption {
+      type = lib.types.str;
+      default = "localhost";
+      description = ''
+        Hostname of the database to connect to.
+      '';
+    };
+
+    databasePort =
+      let
+        dbPorts = {
+          postgresql = 5432;
+          mysql = 3306;
+        };
+      in
+        lib.mkOption {
+          type = lib.types.port;
+          default = dbPorts.${cfg.databaseType};
+          description = ''
+            Port of the database to connect to.
+          '';
+        };
+
+    databaseUseSSL = lib.mkOption {
+      type = lib.types.bool;
+      default = cfg.databaseHost != "localhost";
+      description = ''
+        Whether the database connection should be secured by SSL /
+        TLS.
+      '';
+    };
+
+    databaseCaCert = lib.mkOption {
+      type = lib.types.nullOr lib.types.path;
+      default = null;
+      description = ''
+        The SSL / TLS CA certificate that verifies the identity of the
+        database server.
+
+        Required when PostgreSQL is used and SSL is turned on.
+
+        For MySQL, if left at <literal>null</literal>, the default
+        Java keystore is used, which should suffice if the server
+        certificate is issued by an official CA.
+      '';
+    };
+
+    databaseCreateLocally = lib.mkOption {
+      type = lib.types.bool;
+      default = true;
+      description = ''
+        Whether a database should be automatically created on the
+        local host. Set this to false if you plan on provisioning a
+        local database yourself. This has no effect if
+        services.keycloak.databaseHost is customized.
+      '';
+    };
+
+    databaseUsername = lib.mkOption {
+      type = lib.types.str;
+      default = "keycloak";
+      description = ''
+        Username to use when connecting to an external or manually
+        provisioned database; has no effect when a local database is
+        automatically provisioned.
+      '';
+    };
+
+    databasePasswordFile = lib.mkOption {
+      type = lib.types.path;
+      example = "/run/keys/db_password";
+      description = ''
+        File containing the database password.
+
+        This should be a string, not a Nix path, since Nix paths are
+        copied into the world-readable Nix store.
+      '';
+    };
+
+    package = lib.mkOption {
+      type = lib.types.package;
+      default = pkgs.keycloak;
+      description = ''
+        Keycloak package to use.
+      '';
+    };
+
+    initialAdminPassword = lib.mkOption {
+      type = lib.types.str;
+      default = "changeme";
+      description = ''
+        Initial password set for the <literal>admin</literal>
+        user. The password is not stored safely and should be changed
+        immediately in the admin panel.
+      '';
+    };
+
+    extraConfig = lib.mkOption {
+      type = lib.types.attrs;
+      default = { };
+      example = lib.literalExample ''
+        {
+          "subsystem=keycloak-server" = {
+            "spi=hostname" = {
+              "provider=default" = null;
+              "provider=fixed" = {
+                enabled = true;
+                properties.hostname = "keycloak.example.com";
+              };
+              default-provider = "fixed";
+            };
+          };
+        }
+      '';
+      description = ''
+        Additional Keycloak configuration options to set in
+        <literal>standalone.xml</literal>.
+
+        Options are expressed as a Nix attribute set which matches the
+        structure of the jboss-cli configuration. The configuration is
+        effectively overlayed on top of the default configuration
+        shipped with Keycloak. To remove existing nodes and undefine
+        attributes from the default configuration, set them to
+        <literal>null</literal>.
+
+        The example configuration does the equivalent of the following
+        script, which removes the hostname provider
+        <literal>default</literal>, adds the deprecated hostname
+        provider <literal>fixed</literal> and defines it the default:
+
+        <programlisting>
+        /subsystem=keycloak-server/spi=hostname/provider=default:remove()
+        /subsystem=keycloak-server/spi=hostname/provider=fixed:add(enabled = true, properties = { hostname = "keycloak.example.com" })
+        /subsystem=keycloak-server/spi=hostname:write-attribute(name=default-provider, value="fixed")
+        </programlisting>
+
+        You can discover available options by using the <link
+        xlink:href="http://docs.wildfly.org/21/Admin_Guide.html#Command_Line_Interface">jboss-cli.sh</link>
+        program and by referring to the <link
+        xlink:href="https://www.keycloak.org/docs/latest/server_installation/index.html">Keycloak
+        Server Installation and Configuration Guide</link>.
+      '';
+    };
+
+  };
+
+  config =
+    let
+      # We only want to create a database if we're actually going to connect to it.
+      databaseActuallyCreateLocally = cfg.databaseCreateLocally && cfg.databaseHost == "localhost";
+      createLocalPostgreSQL = databaseActuallyCreateLocally && cfg.databaseType == "postgresql";
+      createLocalMySQL = databaseActuallyCreateLocally && cfg.databaseType == "mysql";
+
+      mySqlCaKeystore = pkgs.runCommandNoCC "mysql-ca-keystore" {} ''
+        ${pkgs.jre}/bin/keytool -importcert -trustcacerts -alias MySQLCACert -file ${cfg.databaseCaCert} -keystore $out -storepass notsosecretpassword -noprompt
+      '';
+
+      keycloakConfig' = builtins.foldl' lib.recursiveUpdate {
+        "interface=public".inet-address = cfg.bindAddress;
+        "socket-binding-group=standard-sockets"."socket-binding=http".port = cfg.httpPort;
+        "subsystem=keycloak-server"."spi=hostname" = {
+          "provider=default" = {
+            enabled = true;
+            properties = {
+              inherit (cfg) frontendUrl forceBackendUrlToFrontendUrl;
+            };
+          };
+        };
+        "subsystem=datasources"."data-source=KeycloakDS" = {
+          max-pool-size = "20";
+          user-name = if databaseActuallyCreateLocally then "keycloak" else cfg.databaseUsername;
+          password = "@db-password@";
+        };
+      } [
+        (lib.optionalAttrs (cfg.databaseType == "postgresql") {
+          "subsystem=datasources" = {
+            "jdbc-driver=postgresql" = {
+              driver-module-name = "org.postgresql";
+              driver-name = "postgresql";
+              driver-xa-datasource-class-name = "org.postgresql.xa.PGXADataSource";
+            };
+            "data-source=KeycloakDS" = {
+              connection-url = "jdbc:postgresql://${cfg.databaseHost}:${builtins.toString cfg.databasePort}/keycloak";
+              driver-name = "postgresql";
+              "connection-properties=ssl".value = lib.boolToString cfg.databaseUseSSL;
+            } // (lib.optionalAttrs (cfg.databaseCaCert != null) {
+              "connection-properties=sslrootcert".value = cfg.databaseCaCert;
+              "connection-properties=sslmode".value = "verify-ca";
+            });
+          };
+        })
+        (lib.optionalAttrs (cfg.databaseType == "mysql") {
+          "subsystem=datasources" = {
+            "jdbc-driver=mysql" = {
+              driver-module-name = "com.mysql";
+              driver-name = "mysql";
+              driver-class-name = "com.mysql.jdbc.Driver";
+            };
+            "data-source=KeycloakDS" = {
+              connection-url = "jdbc:mysql://${cfg.databaseHost}:${builtins.toString cfg.databasePort}/keycloak";
+              driver-name = "mysql";
+              "connection-properties=useSSL".value = lib.boolToString cfg.databaseUseSSL;
+              "connection-properties=requireSSL".value = lib.boolToString cfg.databaseUseSSL;
+              "connection-properties=verifyServerCertificate".value = lib.boolToString cfg.databaseUseSSL;
+              "connection-properties=characterEncoding".value = "UTF-8";
+              valid-connection-checker-class-name = "org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker";
+              validate-on-match = true;
+              exception-sorter-class-name = "org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter";
+            } // (lib.optionalAttrs (cfg.databaseCaCert != null) {
+              "connection-properties=trustCertificateKeyStoreUrl".value = "file:${mySqlCaKeystore}";
+              "connection-properties=trustCertificateKeyStorePassword".value = "notsosecretpassword";
+            });
+          };
+        })
+        (lib.optionalAttrs (cfg.certificatePrivateKeyBundle != null) {
+          "socket-binding-group=standard-sockets"."socket-binding=https".port = cfg.httpsPort;
+          "core-service=management"."security-realm=UndertowRealm"."server-identity=ssl" = {
+            keystore-path = "/run/keycloak/ssl/certificate_private_key_bundle.p12";
+            keystore-password = "notsosecretpassword";
+          };
+          "subsystem=undertow"."server=default-server"."https-listener=https".security-realm = "UndertowRealm";
+        })
+        cfg.extraConfig
+      ];
+
+
+      /* Produces a JBoss CLI script that creates paths and sets
+         attributes matching those described by `attrs`. When the
+         script is run, the existing settings are effectively overlayed
+         by those from `attrs`. Existing attributes can be unset by
+         defining them `null`.
+
+         JBoss paths and attributes / maps are distinguished by their
+         name, where paths follow a `key=value` scheme.
+
+         Example:
+           mkJbossScript {
+             "subsystem=keycloak-server"."spi=hostname" = {
+               "provider=fixed" = null;
+               "provider=default" = {
+                 enabled = true;
+                 properties = {
+                   inherit frontendUrl;
+                   forceBackendUrlToFrontendUrl = false;
+                 };
+               };
+             };
+           }
+           => ''
+             if (outcome != success) of /:read-resource()
+                 /:add()
+             end-if
+             if (outcome != success) of /subsystem=keycloak-server:read-resource()
+                 /subsystem=keycloak-server:add()
+             end-if
+             if (outcome != success) of /subsystem=keycloak-server/spi=hostname:read-resource()
+                 /subsystem=keycloak-server/spi=hostname:add()
+             end-if
+             if (outcome != success) of /subsystem=keycloak-server/spi=hostname/provider=default:read-resource()
+                 /subsystem=keycloak-server/spi=hostname/provider=default:add(enabled = true, properties = { forceBackendUrlToFrontendUrl = false, frontendUrl = "https://keycloak.example.com/auth" })
+             end-if
+             if (result != true) of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="enabled")
+               /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=enabled, value=true)
+             end-if
+             if (result != false) of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="properties.forceBackendUrlToFrontendUrl")
+               /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.forceBackendUrlToFrontendUrl, value=false)
+             end-if
+             if (result != "https://keycloak.example.com/auth") of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="properties.frontendUrl")
+               /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.frontendUrl, value="https://keycloak.example.com/auth")
+             end-if
+             if (outcome != success) of /subsystem=keycloak-server/spi=hostname/provider=fixed:read-resource()
+                 /subsystem=keycloak-server/spi=hostname/provider=fixed:remove()
+             end-if
+           ''
+      */
+      mkJbossScript = attrs:
+        let
+          /* From a JBoss path and an attrset, produces a JBoss CLI
+             snippet that writes the corresponding attributes starting
+             at `path`. Recurses down into subattrsets as necessary,
+             producing the variable name from its full path in the
+             attrset.
+
+             Example:
+               writeAttributes "/subsystem=keycloak-server/spi=hostname/provider=default" {
+                 enabled = true;
+                 properties = {
+                   forceBackendUrlToFrontendUrl = false;
+                   frontendUrl = "https://keycloak.example.com/auth";
+                 };
+               }
+               => ''
+                 if (result != true) of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="enabled")
+                   /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=enabled, value=true)
+                 end-if
+                 if (result != false) of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="properties.forceBackendUrlToFrontendUrl")
+                   /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.forceBackendUrlToFrontendUrl, value=false)
+                 end-if
+                 if (result != "https://keycloak.example.com/auth") of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="properties.frontendUrl")
+                   /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.frontendUrl, value="https://keycloak.example.com/auth")
+                 end-if
+               ''
+          */
+          writeAttributes = path: set:
+            let
+              # JBoss expressions like `${var}` need to be prefixed
+              # with `expression` to evaluate.
+              prefixExpression = string:
+                let
+                  match = (builtins.match ''"\$\{.*}"'' string);
+                in
+                  if match != null then
+                    "expression " + string
+                  else
+                    string;
+
+              writeAttribute = attribute: value:
+                let
+                  type = builtins.typeOf value;
+                in
+                  if type == "set" then
+                    let
+                      names = builtins.attrNames value;
+                    in
+                      builtins.foldl' (text: name: text + (writeAttribute "${attribute}.${name}" value.${name})) "" names
+                  else if value == null then ''
+                    if (outcome == success) of ${path}:read-attribute(name="${attribute}")
+                        ${path}:undefine-attribute(name="${attribute}")
+                    end-if
+                  ''
+                  else if builtins.elem type [ "string" "path" "bool" ] then
+                    let
+                      value' = if type == "bool" then lib.boolToString value else ''"${value}"'';
+                    in ''
+                      if (result != ${prefixExpression value'}) of ${path}:read-attribute(name="${attribute}")
+                        ${path}:write-attribute(name=${attribute}, value=${value'})
+                      end-if
+                    ''
+                  else throw "Unsupported type '${type}' for path '${path}'!";
+            in
+              lib.concatStrings
+                (lib.mapAttrsToList
+                  (attribute: value: (writeAttribute attribute value))
+                  set);
+
+
+          /* Produces an argument list for the JBoss `add()` function,
+             which adds a JBoss path and takes as its arguments the
+             required subpaths and attributes.
+
+             Example:
+               makeArgList {
+                 enabled = true;
+                 properties = {
+                   forceBackendUrlToFrontendUrl = false;
+                   frontendUrl = "https://keycloak.example.com/auth";
+                 };
+               }
+               => ''
+                 enabled = true, properties = { forceBackendUrlToFrontendUrl = false, frontendUrl = "https://keycloak.example.com/auth" }
+               ''
+          */
+          makeArgList = set:
+            let
+              makeArg = attribute: value:
+                let
+                  type = builtins.typeOf value;
+                in
+                  if type == "set" then
+                    "${attribute} = { " + (makeArgList value) + " }"
+                  else if builtins.elem type [ "string" "path" "bool" ] then
+                    "${attribute} = ${if type == "bool" then lib.boolToString value else ''"${value}"''}"
+                  else if value == null then
+                    ""
+                  else
+                    throw "Unsupported type '${type}' for attribute '${attribute}'!";
+            in
+              lib.concatStringsSep ", " (lib.mapAttrsToList makeArg set);
+
+
+          /* Recurses into the `attrs` attrset, beginning at the path
+             resolved from `state.path ++ node`; if `node` is `null`,
+             starts from `state.path`. Only subattrsets that are JBoss
+             paths, i.e. follows the `key=value` format, are recursed
+             into - the rest are considered JBoss attributes / maps.
+          */
+          recurse = state: node:
+            let
+              path = state.path ++ (lib.optional (node != null) node);
+              isPath = name:
+                let
+                  value = lib.getAttrFromPath (path ++ [ name ]) attrs;
+                in
+                  if (builtins.match ".*([=]).*" name) == [ "=" ] then
+                    if builtins.isAttrs value || value == null then
+                      true
+                    else
+                      throw "Parsing path '${lib.concatStringsSep "." (path ++ [ name ])}' failed: JBoss attributes cannot contain '='!"
+                  else
+                    false;
+              jbossPath = "/" + (lib.concatStringsSep "/" path);
+              nodeValue = lib.getAttrFromPath path attrs;
+              children = if !builtins.isAttrs nodeValue then {} else nodeValue;
+              subPaths = builtins.filter isPath (builtins.attrNames children);
+              jbossAttrs = lib.filterAttrs (name: _: !(isPath name)) children;
+            in
+              state // {
+                text = state.text + (
+                  if nodeValue != null then ''
+                    if (outcome != success) of ${jbossPath}:read-resource()
+                        ${jbossPath}:add(${makeArgList jbossAttrs})
+                    end-if
+                  '' + (writeAttributes jbossPath jbossAttrs)
+                  else ''
+                    if (outcome == success) of ${jbossPath}:read-resource()
+                        ${jbossPath}:remove()
+                    end-if
+                  '') + (builtins.foldl' recurse { text = ""; inherit path; } subPaths).text;
+              };
+        in
+          (recurse { text = ""; path = []; } null).text;
+
+
+      jbossCliScript = pkgs.writeText "jboss-cli-script" (mkJbossScript keycloakConfig');
+
+      keycloakConfig = pkgs.runCommandNoCC "keycloak-config" {} ''
+        export JBOSS_BASE_DIR="$(pwd -P)";
+        export JBOSS_MODULEPATH="${cfg.package}/modules";
+        export JBOSS_LOG_DIR="$JBOSS_BASE_DIR/log";
+
+        cp -r ${cfg.package}/standalone/configuration .
+        chmod -R u+rwX ./configuration
+
+        mkdir -p {deployments,ssl}
+
+        "${cfg.package}/bin/standalone.sh"&
+
+        attempt=1
+        max_attempts=30
+        while ! ${cfg.package}/bin/jboss-cli.sh --connect ':read-attribute(name=server-state)'; do
+            if [[ "$attempt" == "$max_attempts" ]]; then
+                echo "ERROR: Could not connect to Keycloak after $attempt attempts! Failing.." >&2
+                exit 1
+            fi
+            echo "Keycloak not fully started yet, retrying.. ($attempt/$max_attempts)"
+            sleep 1
+            (( attempt++ ))
+        done
+
+        ${cfg.package}/bin/jboss-cli.sh --connect --file=${jbossCliScript} --echo-command
+
+        cp configuration/standalone.xml $out
+      '';
+    in
+      lib.mkIf cfg.enable {
+
+        assertions = [
+          {
+            assertion = (cfg.databaseUseSSL && cfg.databaseType == "postgresql") -> (cfg.databaseCaCert != null);
+            message = ''A CA certificate must be specified (in 'services.keycloak.databaseCaCert') when PostgreSQL is used with SSL'';
+          }
+        ];
+
+        environment.systemPackages = [ cfg.package ];
+
+        systemd.services.keycloakPostgreSQLInit = lib.mkIf createLocalPostgreSQL {
+          after = [ "postgresql.service" ];
+          before = [ "keycloak.service" ];
+          bindsTo = [ "postgresql.service" ];
+          serviceConfig = {
+            Type = "oneshot";
+            RemainAfterExit = true;
+            User = "postgres";
+            Group = "postgres";
+          };
+          script = ''
+            set -eu
+
+            PSQL=${config.services.postgresql.package}/bin/psql
+
+            db_password="$(<'${cfg.databasePasswordFile}')"
+            $PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='keycloak'" | grep -q 1 || $PSQL -tAc "CREATE ROLE keycloak WITH LOGIN PASSWORD '$db_password' CREATEDB"
+            $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'keycloak'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "keycloak" OWNER "keycloak"'
+          '';
+        };
+
+        systemd.services.keycloakMySQLInit = lib.mkIf createLocalMySQL {
+          after = [ "mysql.service" ];
+          before = [ "keycloak.service" ];
+          bindsTo = [ "mysql.service" ];
+          serviceConfig = {
+            Type = "oneshot";
+            RemainAfterExit = true;
+            User = config.services.mysql.user;
+            Group = config.services.mysql.group;
+          };
+          script = ''
+            set -eu
+
+            db_password="$(<'${cfg.databasePasswordFile}')"
+            ( echo "CREATE USER IF NOT EXISTS 'keycloak'@'localhost' IDENTIFIED BY '$db_password';"
+              echo "CREATE DATABASE keycloak CHARACTER SET utf8 COLLATE utf8_unicode_ci;"
+              echo "GRANT ALL PRIVILEGES ON keycloak.* TO 'keycloak'@'localhost';"
+            ) | ${config.services.mysql.package}/bin/mysql -N
+          '';
+        };
+
+        systemd.services.keycloak =
+          let
+            databaseServices =
+              if createLocalPostgreSQL then [
+                "keycloakPostgreSQLInit.service" "postgresql.service"
+              ]
+              else if createLocalMySQL then [
+                "keycloakMySQLInit.service" "mysql.service"
+              ]
+              else [ ];
+          in {
+            after = databaseServices;
+            bindsTo = databaseServices;
+            wantedBy = [ "multi-user.target" ];
+            environment = {
+              JBOSS_LOG_DIR = "/var/log/keycloak";
+              JBOSS_BASE_DIR = "/run/keycloak";
+              JBOSS_MODULEPATH = "${cfg.package}/modules";
+            };
+            serviceConfig = {
+              ExecStartPre = let
+                startPreFullPrivileges = ''
+                  set -eu
+
+                  install -T -m 0400 -o keycloak -g keycloak '${cfg.databasePasswordFile}' /run/keycloak/secrets/db_password
+                '' + lib.optionalString (cfg.certificatePrivateKeyBundle != null) ''
+                  install -T -m 0400 -o keycloak -g keycloak '${cfg.certificatePrivateKeyBundle}' /run/keycloak/secrets/ssl_cert_pk_bundle
+                '';
+                startPre = ''
+                  set -eu
+
+                  install -m 0600 ${cfg.package}/standalone/configuration/*.properties /run/keycloak/configuration
+                  install -T -m 0600 ${keycloakConfig} /run/keycloak/configuration/standalone.xml
+
+                  db_password="$(</run/keycloak/secrets/db_password)"
+                  ${pkgs.replace}/bin/replace-literal -fe '@db-password@' "$db_password" /run/keycloak/configuration/standalone.xml
+
+                  export JAVA_OPTS=-Djboss.server.config.user.dir=/run/keycloak/configuration
+                  ${cfg.package}/bin/add-user-keycloak.sh -u admin -p '${cfg.initialAdminPassword}'
+                '' + lib.optionalString (cfg.certificatePrivateKeyBundle != null) ''
+                  pushd /run/keycloak/ssl/
+                  cat /run/keycloak/secrets/ssl_cert_pk_bundle <(echo) /etc/ssl/certs/ca-certificates.crt > allcerts.pem
+                  ${pkgs.openssl}/bin/openssl pkcs12 -export -in /run/keycloak/secrets/ssl_cert_pk_bundle -chain \
+                                                     -name "${cfg.frontendUrl}" -out certificate_private_key_bundle.p12 \
+                                                     -CAfile allcerts.pem -passout pass:notsosecretpassword
+                  popd
+                '';
+              in [
+                "+${pkgs.writeShellScript "keycloak-start-pre-full-privileges" startPreFullPrivileges}"
+                "${pkgs.writeShellScript "keycloak-start-pre" startPre}"
+              ];
+              ExecStart = "${cfg.package}/bin/standalone.sh";
+              User = "keycloak";
+              Group = "keycloak";
+              DynamicUser = true;
+              RuntimeDirectory = map (p: "keycloak/" + p) [
+                "secrets"
+                "configuration"
+                "deployments"
+                "data"
+                "ssl"
+                "log"
+                "tmp"
+              ];
+              RuntimeDirectoryMode = 0700;
+              LogsDirectory = "keycloak";
+              AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+            };
+          };
+
+        services.postgresql.enable = lib.mkDefault createLocalPostgreSQL;
+        services.mysql.enable = lib.mkDefault createLocalMySQL;
+        services.mysql.package = lib.mkIf createLocalMySQL pkgs.mysql;
+      };
+
+  meta.doc = ./keycloak.xml;
+}
diff --git a/nixpkgs/nixos/modules/services/web-apps/keycloak.xml b/nixpkgs/nixos/modules/services/web-apps/keycloak.xml
new file mode 100644
index 000000000000..ca5e223eee46
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/keycloak.xml
@@ -0,0 +1,205 @@
+<chapter xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         version="5.0"
+         xml:id="module-services-keycloak">
+ <title>Keycloak</title>
+ <para>
+   <link xlink:href="https://www.keycloak.org/">Keycloak</link> is an
+   open source identity and access management server with support for
+   <link xlink:href="https://openid.net/connect/">OpenID
+   Connect</link>, <link xlink:href="https://oauth.net/2/">OAUTH
+   2.0</link> and <link
+   xlink:href="https://en.wikipedia.org/wiki/SAML_2.0">SAML
+   2.0</link>.
+ </para>
+   <section xml:id="module-services-keycloak-admin">
+     <title>Administration</title>
+     <para>
+       An administrative user with the username
+       <literal>admin</literal> is automatically created in the
+       <literal>master</literal> realm. Its initial password can be
+       configured by setting <xref linkend="opt-services.keycloak.initialAdminPassword" />
+       and defaults to <literal>changeme</literal>. The password is
+       not stored safely and should be changed immediately in the
+       admin panel.
+     </para>
+
+     <para>
+       Refer to the <link
+       xlink:href="https://www.keycloak.org/docs/latest/server_admin/index.html#admin-console">Admin
+       Console section of the Keycloak Server Administration Guide</link> for
+       information on how to administer your
+       <productname>Keycloak</productname> instance.
+     </para>
+   </section>
+
+   <section xml:id="module-services-keycloak-database">
+     <title>Database access</title>
+     <para>
+       <productname>Keycloak</productname> can be used with either
+       <productname>PostgreSQL</productname> or
+       <productname>MySQL</productname>. Which one is used can be
+       configured in <xref
+       linkend="opt-services.keycloak.databaseType" />. The selected
+       database will automatically be enabled and a database and role
+       created unless <xref
+       linkend="opt-services.keycloak.databaseHost" /> is changed from
+       its default of <literal>localhost</literal> or <xref
+       linkend="opt-services.keycloak.databaseCreateLocally" /> is set
+       to <literal>false</literal>.
+     </para>
+
+     <para>
+       External database access can also be configured by setting
+       <xref linkend="opt-services.keycloak.databaseHost" />, <xref
+       linkend="opt-services.keycloak.databaseUsername" />, <xref
+       linkend="opt-services.keycloak.databaseUseSSL" /> and <xref
+       linkend="opt-services.keycloak.databaseCaCert" /> as
+       appropriate. Note that you need to manually create a database
+       called <literal>keycloak</literal> and allow the configured
+       database user full access to it.
+     </para>
+
+     <para>
+       <xref linkend="opt-services.keycloak.databasePasswordFile" />
+       must be set to the path to a file containing the password used
+       to log in to the database. If <xref linkend="opt-services.keycloak.databaseHost" />
+       and <xref linkend="opt-services.keycloak.databaseCreateLocally" />
+       are kept at their defaults, the database role
+       <literal>keycloak</literal> with that password is provisioned
+       on the local database instance.
+     </para>
+
+     <warning>
+       <para>
+         The path should be provided as a string, not a Nix path, since Nix
+         paths are copied into the world readable Nix store.
+       </para>
+     </warning>
+   </section>
+
+   <section xml:id="module-services-keycloak-frontendurl">
+     <title>Frontend URL</title>
+     <para>
+       The frontend URL is used as base for all frontend requests and
+       must be configured through <xref linkend="opt-services.keycloak.frontendUrl" />.
+       It should normally include a trailing <literal>/auth</literal>
+       (the default web context).
+     </para>
+
+     <para>
+       <xref linkend="opt-services.keycloak.forceBackendUrlToFrontendUrl" />
+       determines whether Keycloak should force all requests to go
+       through the frontend URL. By default,
+       <productname>Keycloak</productname> allows backend requests to
+       instead use its local hostname or IP address and may also
+       advertise it to clients through its OpenID Connect Discovery
+       endpoint.
+     </para>
+
+     <para>
+       See the <link
+       xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">Hostname
+       section of the Keycloak Server Installation and Configuration
+       Guide</link> for more information.
+     </para>
+   </section>
+
+   <section xml:id="module-services-keycloak-tls">
+     <title>Setting up TLS/SSL</title>
+     <para>
+       By default, <productname>Keycloak</productname> won't accept
+       unsecured HTTP connections originating from outside its local
+       network.
+     </para>
+
+     <para>
+       For HTTPS support, a TLS certificate and private key is
+       required. They should be <link
+       xlink:href="https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail">PEM
+       formatted</link> and concatenated into a single file. The path
+       to this file should be configured in
+       <xref linkend="opt-services.keycloak.certificatePrivateKeyBundle" />.
+     </para>
+
+     <warning>
+       <para>
+         The path should be provided as a string, not a Nix path,
+         since Nix paths are copied into the world readable Nix store.
+       </para>
+     </warning>
+   </section>
+
+   <section xml:id="module-services-keycloak-extra-config">
+     <title>Additional configuration</title>
+     <para>
+       Additional Keycloak configuration options, for which no
+       explicit <productname>NixOS</productname> options are provided,
+       can be set in <xref linkend="opt-services.keycloak.extraConfig" />.
+     </para>
+
+     <para>
+       Options are expressed as a Nix attribute set which matches the
+       structure of the jboss-cli configuration. The configuration is
+       effectively overlayed on top of the default configuration
+       shipped with Keycloak. To remove existing nodes and undefine
+       attributes from the default configuration, set them to
+       <literal>null</literal>.
+     </para>
+     <para>
+       For example, the following script, which removes the hostname
+       provider <literal>default</literal>, adds the deprecated
+       hostname provider <literal>fixed</literal> and defines it the
+       default:
+
+<programlisting>
+/subsystem=keycloak-server/spi=hostname/provider=default:remove()
+/subsystem=keycloak-server/spi=hostname/provider=fixed:add(enabled = true, properties = { hostname = "keycloak.example.com" })
+/subsystem=keycloak-server/spi=hostname:write-attribute(name=default-provider, value="fixed")
+</programlisting>
+
+       would be expressed as
+
+<programlisting>
+services.keycloak.extraConfig = {
+  "subsystem=keycloak-server" = {
+    "spi=hostname" = {
+      "provider=default" = null;
+      "provider=fixed" = {
+        enabled = true;
+        properties.hostname = "keycloak.example.com";
+      };
+      default-provider = "fixed";
+    };
+  };
+};
+</programlisting>
+     </para>
+     <para>
+       You can discover available options by using the <link
+       xlink:href="http://docs.wildfly.org/21/Admin_Guide.html#Command_Line_Interface">jboss-cli.sh</link>
+       program and by referring to the <link
+       xlink:href="https://www.keycloak.org/docs/latest/server_installation/index.html">Keycloak
+       Server Installation and Configuration Guide</link>.
+     </para>
+   </section>
+
+   <section xml:id="module-services-keycloak-example-config">
+     <title>Example configuration</title>
+     <para>
+       A basic configuration with some custom settings could look like this:
+<programlisting>
+services.keycloak = {
+  <link linkend="opt-services.keycloak.enable">enable</link> = true;
+  <link linkend="opt-services.keycloak.initialAdminPassword">initialAdminPassword</link> = "e6Wcm0RrtegMEHl";  # change on first login
+  <link linkend="opt-services.keycloak.frontendUrl">frontendUrl</link> = "https://keycloak.example.com/auth";
+  <link linkend="opt-services.keycloak.forceBackendUrlToFrontendUrl">forceBackendUrlToFrontendUrl</link> = true;
+  <link linkend="opt-services.keycloak.certificatePrivateKeyBundle">certificatePrivateKeyBundle</link> = "/run/keys/ssl_cert";
+  <link linkend="opt-services.keycloak.databasePasswordFile">databasePasswordFile</link> = "/run/keys/db_password";
+};
+</programlisting>
+     </para>
+
+   </section>
+ </chapter>
diff --git a/nixpkgs/nixos/modules/services/web-apps/moinmoin.nix b/nixpkgs/nixos/modules/services/web-apps/moinmoin.nix
index dc7abce2a5cb..3a876f75f4a4 100644
--- a/nixpkgs/nixos/modules/services/web-apps/moinmoin.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/moinmoin.nix
@@ -224,6 +224,8 @@ in
               chmod -R u+w ${dataDir}/${wikiIdent}/underlay
             '';
 
+            startLimitIntervalSec = 30;
+
             serviceConfig = {
               User = user;
               Group = group;
@@ -237,7 +239,6 @@ in
 
               Restart = "on-failure";
               RestartSec = "2s";
-              StartLimitIntervalSec = "30s";
 
               StateDirectory = "moin/${wikiIdent}";
               StateDirectoryMode = "0750";
diff --git a/nixpkgs/nixos/modules/services/web-apps/moodle.nix b/nixpkgs/nixos/modules/services/web-apps/moodle.nix
index f45eaa24d544..8887136ea5e7 100644
--- a/nixpkgs/nixos/modules/services/web-apps/moodle.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/moodle.nix
@@ -57,7 +57,7 @@ let
   pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql";
 
   phpExt = pkgs.php.withExtensions
-        ({ enabled, all }: with all; [ iconv mbstring curl openssl tokenizer xmlrpc soap ctype zip gd simplexml dom  intl json sqlite3 pgsql pdo_sqlite pdo_pgsql pdo_odbc pdo_mysql pdo mysqli session zlib xmlreader fileinfo ]);
+        ({ enabled, all }: with all; [ iconv mbstring curl openssl tokenizer xmlrpc soap ctype zip gd simplexml dom  intl json sqlite3 pgsql pdo_sqlite pdo_pgsql pdo_odbc pdo_mysql pdo mysqli session zlib xmlreader fileinfo filter ]);
 in
 {
   # interface
diff --git a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
index 7da119758fc9..da019aa25079 100644
--- a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
@@ -39,7 +39,7 @@ let
     export NEXTCLOUD_CONFIG_DIR="${cfg.home}/config"
     $sudo \
       ${phpPackage}/bin/php \
-      occ $*
+      occ "$@"
   '';
 
   inherit (config.system) stateVersion;
@@ -85,7 +85,7 @@ in {
     package = mkOption {
       type = types.package;
       description = "Which package to use for the Nextcloud instance.";
-      relatedPackages = [ "nextcloud17" "nextcloud18" "nextcloud19" ];
+      relatedPackages = [ "nextcloud18" "nextcloud19" "nextcloud20" ];
     };
 
     maxUploadSize = mkOption {
@@ -330,37 +330,28 @@ in {
         }
       ];
 
-      warnings = []
-        ++ (optional (cfg.poolConfig != null) ''
-          Using config.services.nextcloud.poolConfig is deprecated and will become unsupported in a future release.
-          Please migrate your configuration to config.services.nextcloud.poolSettings.
-        '')
-        ++ (optional (versionOlder cfg.package.version "18") ''
-          A legacy Nextcloud install (from before NixOS 20.03) may be installed.
-
-          You're currently deploying an older version of Nextcloud. This may be needed
-          since Nextcloud doesn't allow major version upgrades that skip multiple
-          versions (i.e. an upgrade from 16 is possible to 17, but not 16 to 18).
+      warnings = let
+        latest = 20;
+        upgradeWarning = major: nixos:
+          ''
+            A legacy Nextcloud install (from before NixOS ${nixos}) may be installed.
 
-          It is assumed that Nextcloud will be upgraded from version 16 to 17.
+            After nextcloud${toString major} is installed successfully, you can safely upgrade
+            to ${toString (major + 1)}. The latest version available is nextcloud${toString latest}.
 
-           * If this is a fresh install, there will be no upgrade to do now.
+            Please note that Nextcloud doesn't support upgrades across multiple major versions
+            (i.e. an upgrade from 16 is possible to 17, but not 16 to 18).
 
-           * If this server already had Nextcloud installed, first deploy this to your
-             server, and wait until the upgrade to 17 is finished.
-
-          Then, set `services.nextcloud.package` to `pkgs.nextcloud18` to upgrade to
-          Nextcloud version 18. Please note that Nextcloud 19 is already out and it's
-          recommended to upgrade to nextcloud19 after that.
+            The package can be upgraded by explicitly declaring the service-option
+            `services.nextcloud.package`.
+          '';
+      in (optional (cfg.poolConfig != null) ''
+          Using config.services.nextcloud.poolConfig is deprecated and will become unsupported in a future release.
+          Please migrate your configuration to config.services.nextcloud.poolSettings.
         '')
-        ++ (optional (versionOlder cfg.package.version "19") ''
-          A legacy Nextcloud install (from before NixOS 20.09/unstable) may be installed.
-
-          If/After nextcloud18 is installed successfully, you can safely upgrade to
-          nextcloud19. If not, please upgrade to nextcloud18 first since Nextcloud doesn't
-          support upgrades that skip multiple versions (i.e. an upgrade from 17 to 19 isn't
-          possible, but an upgrade from 18 to 19).
-        '');
+        ++ (optional (versionOlder cfg.package.version "18") (upgradeWarning 17 "20.03"))
+        ++ (optional (versionOlder cfg.package.version "19") (upgradeWarning 18 "20.09"))
+        ++ (optional (versionOlder cfg.package.version "20") (upgradeWarning 19 "21.03"));
 
       services.nextcloud.package = with pkgs;
         mkDefault (
@@ -372,7 +363,8 @@ in {
             ''
           else if versionOlder stateVersion "20.03" then nextcloud17
           else if versionOlder stateVersion "20.09" then nextcloud18
-          else nextcloud19
+          else if versionOlder stateVersion "21.03" then nextcloud19
+          else nextcloud20
         );
     }
 
@@ -399,7 +391,9 @@ in {
                 $file = "${c.dbpassFile}";
                 if (!file_exists($file)) {
                   throw new \RuntimeException(sprintf(
-                    "Cannot start Nextcloud, dbpass file %s set by NixOS doesn't exist!",
+                    "Cannot start Nextcloud, dbpass file %s set by NixOS doesn't seem to "
+                    . "exist! Please make sure that the file exists and has appropriate "
+                    . "permissions for user & group 'nextcloud'!",
                     $file
                   ));
                 }
@@ -435,7 +429,7 @@ in {
               then ''"$(<"${toString c.dbpassFile}")"''
               else if c.dbpass != null
               then ''"${toString c.dbpass}"''
-              else null;
+              else ''""'';
             adminpass = if c.adminpassFile != null
               then ''"$(<"${toString c.adminpassFile}")"''
               else ''"${toString c.adminpass}"'';
@@ -449,8 +443,7 @@ in {
               ${if c.dbhost != null then "--database-host" else null} = ''"${c.dbhost}"'';
               ${if c.dbport != null then "--database-port" else null} = ''"${toString c.dbport}"'';
               ${if c.dbuser != null then "--database-user" else null} = ''"${c.dbuser}"'';
-              ${if (any (x: x != null) [c.dbpass c.dbpassFile])
-                 then "--database-pass" else null} = dbpass;
+              "--database-pass" = dbpass;
               ${if c.dbtableprefix != null
                 then "--database-table-prefix" else null} = ''"${toString c.dbtableprefix}"'';
               "--admin-user" = ''"${c.adminuser}"'';
@@ -542,7 +535,10 @@ in {
       environment.systemPackages = [ occ ];
 
       services.nginx.enable = mkDefault true;
-      services.nginx.virtualHosts.${cfg.hostName} = {
+
+      services.nginx.virtualHosts.${cfg.hostName} = let
+        major = toInt (versions.major cfg.package.version);
+      in {
         root = cfg.package;
         locations = {
           "= /robots.txt" = {
@@ -555,7 +551,7 @@ in {
           };
           "/" = {
             priority = 900;
-            extraConfig = "try_files $uri $uri/ /index.php$request_uri;";
+            extraConfig = "rewrite ^ /index.php;";
           };
           "~ ^/store-apps" = {
             priority = 201;
@@ -579,7 +575,7 @@ in {
           "~ ^/(?:\\.|autotest|occ|issue|indie|db_|console)".extraConfig = ''
             return 404;
           '';
-          "~ \\.php(?:$|/)" = {
+          "~ ^\\/(?:index|remote|public|cron|core\\/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|oc[ms]-provider\\/.+|.+\\/richdocumentscode\\/proxy)\\.php(?:$|\\/)" = {
             priority = 500;
             extraConfig = ''
               include ${config.services.nginx.package}/conf/fastcgi.conf;
@@ -597,20 +593,19 @@ in {
               fastcgi_read_timeout 120s;
             '';
           };
-          "~ \\.(?:css|js|svg|gif|map)$".extraConfig = ''
+          "~ \\.(?:css|js|woff2?|svg|gif|map)$".extraConfig = ''
             try_files $uri /index.php$request_uri;
             expires 6M;
             access_log off;
           '';
-          "~ \\.woff2?$".extraConfig = ''
-            try_files $uri /index.php$request_uri;
-            expires 7d;
-            access_log off;
-          '';
           "~ ^\\/(?:updater|ocs-provider|ocm-provider)(?:$|\\/)".extraConfig = ''
             try_files $uri/ =404;
             index index.php;
           '';
+          "~ \\.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$".extraConfig = ''
+            try_files $uri /index.php$request_uri;
+            access_log off;
+          '';
         };
         extraConfig = ''
           index index.php index.html /index.php$request_uri;
diff --git a/nixpkgs/nixos/modules/services/web-apps/plantuml-server.nix b/nixpkgs/nixos/modules/services/web-apps/plantuml-server.nix
new file mode 100644
index 000000000000..a39f594c274c
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/plantuml-server.nix
@@ -0,0 +1,123 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.plantuml-server;
+
+in
+
+{
+  options = {
+    services.plantuml-server = {
+      enable = mkEnableOption "PlantUML server";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.plantuml-server;
+        description = "PlantUML server package to use";
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "plantuml";
+        description = "User which runs PlantUML server.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "plantuml";
+        description = "Group which runs PlantUML server.";
+      };
+
+      home = mkOption {
+        type = types.str;
+        default = "/var/lib/plantuml";
+        description = "Home directory of the PlantUML server instance.";
+      };
+
+      listenHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = "Host to listen on.";
+      };
+
+      listenPort = mkOption {
+        type = types.int;
+        default = 8080;
+        description = "Port to listen on.";
+      };
+
+      plantumlLimitSize = mkOption {
+        type = types.int;
+        default = 4096;
+        description = "Limits image width and height.";
+      };
+
+      graphvizPackage = mkOption {
+        type = types.package;
+        default = pkgs.graphviz_2_32;
+        description = "Package containing the dot executable.";
+      };
+
+      plantumlStats = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Set it to on to enable statistics report (https://plantuml.com/statistics-report).";
+      };
+
+      httpAuthorization = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "When calling the proxy endpoint, the value of HTTP_AUTHORIZATION will be used to set the HTTP Authorization header.";
+      };
+
+      allowPlantumlInclude = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Enables !include processing which can read files from the server into diagrams. Files are read relative to the current working directory.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.users.${cfg.user} = {
+      isSystemUser = true;
+      group = cfg.group;
+      home = cfg.home;
+      createHome = true;
+    };
+
+    users.groups.${cfg.group} = {};
+
+    systemd.services.plantuml-server = {
+      description = "PlantUML server";
+      wantedBy = [ "multi-user.target" ];
+      path = [ cfg.home ];
+      environment = {
+        PLANTUML_LIMIT_SIZE = builtins.toString cfg.plantumlLimitSize;
+        GRAPHVIZ_DOT = "${cfg.graphvizPackage}/bin/dot";
+        PLANTUML_STATS = if cfg.plantumlStats then "on" else "off";
+        HTTP_AUTHORIZATION = cfg.httpAuthorization;
+        ALLOW_PLANTUML_INCLUDE = if cfg.allowPlantumlInclude then "true" else "false";
+      };
+      script = ''
+      ${pkgs.jre}/bin/java \
+        -jar ${pkgs.jetty}/start.jar \
+          --module=deploy,http,jsp \
+          jetty.home=${pkgs.jetty} \
+          jetty.base=${cfg.package} \
+          jetty.http.host=${cfg.listenHost} \
+          jetty.http.port=${builtins.toString cfg.listenPort}
+      '';
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        PrivateTmp = true;
+      };
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ truh ];
+}
diff --git a/nixpkgs/nixos/modules/services/web-apps/shiori.nix b/nixpkgs/nixos/modules/services/web-apps/shiori.nix
index 1817a2039352..9083ddfa2206 100644
--- a/nixpkgs/nixos/modules/services/web-apps/shiori.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/shiori.nix
@@ -37,11 +37,60 @@ in {
       description = "Shiori simple bookmarks manager";
       wantedBy = [ "multi-user.target" ];
 
+      environment.SHIORI_DIR = "/var/lib/shiori";
+
       serviceConfig = {
         ExecStart = "${package}/bin/shiori serve --address '${address}' --port '${toString port}'";
+
         DynamicUser = true;
-        Environment = "SHIORI_DIR=/var/lib/shiori";
         StateDirectory = "shiori";
+        # As the RootDirectory
+        RuntimeDirectory = "shiori";
+
+        # Security options
+
+        BindReadOnlyPaths = [
+          "/nix/store"
+
+          # For SSL certificates, and the resolv.conf
+          "/etc"
+        ];
+
+        CapabilityBoundingSet = "";
+
+        DeviceAllow = "";
+
+        LockPersonality = true;
+
+        MemoryDenyWriteExecute = true;
+
+        PrivateDevices = true;
+        PrivateUsers = true;
+
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+
+        RestrictNamespaces = true;
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+
+        RootDirectory = "/run/shiori";
+
+        SystemCallArchitectures = "native";
+        SystemCallErrorNumber = "EPERM";
+        SystemCallFilter = [
+          "@system-service"
+
+          "~@chown" "~@cpu-emulation" "~@debug" "~@ipc" "~@keyring" "~@memlock"
+          "~@module" "~@obsolete" "~@privileged" "~@process" "~@raw-io"
+          "~@resources" "~@setuid"
+        ];
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/web-apps/zabbix.nix b/nixpkgs/nixos/modules/services/web-apps/zabbix.nix
index 007195128347..e94861a90b5a 100644
--- a/nixpkgs/nixos/modules/services/web-apps/zabbix.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/zabbix.nix
@@ -3,7 +3,7 @@
 let
 
   inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types;
-  inherit (lib) literalExample mapAttrs optionalString;
+  inherit (lib) literalExample mapAttrs optionalString versionAtLeast;
 
   cfg = config.services.zabbixWeb;
   fpm = config.services.phpfpm.pools.zabbix;
@@ -28,6 +28,8 @@ let
     $ZBX_SERVER_PORT = '${toString cfg.server.port}';
     $ZBX_SERVER_NAME = ''';
     $IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
+
+    ${cfg.extraConfig}
   '';
 
 in
@@ -143,6 +145,14 @@ in
         '';
       };
 
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional configuration to be copied verbatim into <filename>zabbix.conf.php</filename>.
+        '';
+      };
+
     };
   };
 
@@ -150,6 +160,10 @@ in
 
   config = mkIf cfg.enable {
 
+    services.zabbixWeb.extraConfig = optionalString ((versionAtLeast config.system.stateVersion "20.09") && (versionAtLeast cfg.package.version "5.0.0")) ''
+      $DB['DOUBLE_IEEE754'] = 'true';
+    '';
+
     systemd.tmpfiles.rules = [
       "d '${stateDir}' 0750 ${user} ${group} - -"
       "d '${stateDir}/session' 0750 ${user} ${config.services.httpd.group} - -"
diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
index 6dd1c85132c9..de3c7d693d47 100644
--- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -126,6 +126,13 @@ let
     </IfModule>
   '';
 
+  luaSetPaths = ''
+    <IfModule mod_lua.c>
+      LuaPackageCPath ${cfg.package.lua5}/lib/lua/${cfg.package.lua5.lua.luaversion}/?.so
+      LuaPackagePath  ${cfg.package.lua5}/share/lua/${cfg.package.lua5.lua.luaversion}/?.lua
+    </IfModule>
+  '';
+
   mkVHostConf = hostOpts:
     let
       adminAddr = if hostOpts.adminAddr != null then hostOpts.adminAddr else cfg.adminAddr;
@@ -326,6 +333,8 @@ let
 
     ${sslConf}
 
+    ${if cfg.package.luaSupport then luaSetPaths else ""}
+
     # Fascist default - deny access to everything.
     <Directory />
         Options FollowSymLinks
@@ -693,9 +702,6 @@ in
 
     services.httpd.phpOptions =
       ''
-        ; Needed for PHP's mail() function.
-        sendmail_path = ${pkgs.system-sendmail}/bin/sendmail -t -i
-
         ; Don't advertise PHP
         expose_php = off
       '' + optionalString (config.time.timeZone != null) ''
@@ -753,8 +759,8 @@ in
             # Get rid of old semaphores.  These tend to accumulate across
             # server restarts, eventually preventing it from restarting
             # successfully.
-            for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${cfg.user} ' | cut -f2 -d ' '); do
-                ${pkgs.utillinux}/bin/ipcrm -s $i
+            for i in $(${pkgs.util-linux}/bin/ipcs -s | grep ' ${cfg.user} ' | cut -f2 -d ' '); do
+                ${pkgs.util-linux}/bin/ipcrm -s $i
             done
           '';
 
diff --git a/nixpkgs/nixos/modules/services/web-servers/caddy.nix b/nixpkgs/nixos/modules/services/web-servers/caddy.nix
index dda26fe491a1..297b73273392 100644
--- a/nixpkgs/nixos/modules/services/web-servers/caddy.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/caddy.nix
@@ -6,8 +6,6 @@ let
   cfg = config.services.caddy;
   configFile = pkgs.writeText "Caddyfile" cfg.config;
 
-  # v2-specific options
-  isCaddy2 = versionAtLeast cfg.package.version "2.0";
   tlsConfig = {
     apps.tls.automation.policies = [{
       issuer = {
@@ -26,6 +24,10 @@ let
     ${pkgs.jq}/bin/jq -s '.[0] * .[1]' ${adaptedConfig} ${tlsJSON} > $out
   '';
 in {
+  imports = [
+    (mkRemovedOptionModule [ "services" "caddy" "agree" ] "this option is no longer necessary for Caddy 2")
+  ];
+
   options.services.caddy = {
     enable = mkEnableOption "Caddy web server";
 
@@ -50,7 +52,7 @@ in {
       example = "nginx";
       type = types.str;
       description = ''
-        Name of the config adapter to use. Not applicable to Caddy v1.
+        Name of the config adapter to use.
         See https://caddyserver.com/docs/config-adapters for the full list.
       '';
     };
@@ -68,12 +70,6 @@ in {
       description = "Email address (for Let's Encrypt certificate)";
     };
 
-    agree = mkOption {
-      default = false;
-      type = types.bool;
-      description = "Agree to Let's Encrypt Subscriber Agreement";
-    };
-
     dataDir = mkOption {
       default = "/var/lib/caddy";
       type = types.path;
@@ -90,11 +86,10 @@ in {
     package = mkOption {
       default = pkgs.caddy;
       defaultText = "pkgs.caddy";
-      example = "pkgs.caddy1";
+      example = "pkgs.caddy";
       type = types.package;
       description = ''
         Caddy package to use.
-        To use Caddy v1 (obsolete), set this to <literal>pkgs.caddy1</literal>.
       '';
     };
   };
@@ -106,27 +101,15 @@ in {
       after = [ "network-online.target" ];
       wants = [ "network-online.target" ]; # systemd-networkd-wait-online.service
       wantedBy = [ "multi-user.target" ];
-      environment = mkIf (versionAtLeast config.system.stateVersion "17.09" && !isCaddy2)
-        { CADDYPATH = cfg.dataDir; };
+      startLimitIntervalSec = 14400;
+      startLimitBurst = 10;
       serviceConfig = {
-        ExecStart = if isCaddy2 then ''
-          ${cfg.package}/bin/caddy run --config ${configJSON}
-        '' else ''
-          ${cfg.package}/bin/caddy -log stdout -log-timestamps=false \
-            -root=/var/tmp -conf=${configFile} \
-            -ca=${cfg.ca} -email=${cfg.email} ${optionalString cfg.agree "-agree"}
-        '';
-        ExecReload =
-          if isCaddy2 then
-            "${cfg.package}/bin/caddy reload --config ${configJSON}"
-          else
-            "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
+        ExecStart = "${cfg.package}/bin/caddy run --config ${configJSON}";
+        ExecReload = "${cfg.package}/bin/caddy reload --config ${configJSON}";
         Type = "simple";
         User = "caddy";
         Group = "caddy";
         Restart = "on-abnormal";
-        StartLimitIntervalSec = 14400;
-        StartLimitBurst = 10;
         AmbientCapabilities = "cap_net_bind_service";
         CapabilityBoundingSet = "cap_net_bind_service";
         NoNewPrivileges = true;
diff --git a/nixpkgs/nixos/modules/services/web-servers/molly-brown.nix b/nixpkgs/nixos/modules/services/web-servers/molly-brown.nix
index e9052a184b2d..e0587f3b4716 100644
--- a/nixpkgs/nixos/modules/services/web-servers/molly-brown.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/molly-brown.nix
@@ -4,23 +4,8 @@ with lib;
 
 let
   cfg = config.services.molly-brown;
-
-  settingsType = with types;
-    attrsOf (oneOf [
-      int
-      str
-      (listOf str)
-      (attrsOf (oneOf [ int str (listOf str) (attrsOf str) ]))
-    ]) // {
-      description = "primitive expression convertable to TOML";
-    };
-
-  configFile = pkgs.runCommand "molly-brown.toml" {
-    buildInputs = [ pkgs.remarshal ];
-    preferLocalBuild = true;
-    passAsFile = [ "settings" ];
-    settings = builtins.toJSON cfg.settings;
-  } "remarshal -if json -of toml < $settingsPath > $out";
+  settingsFormat = pkgs.formats.toml { };
+ configFile = settingsFormat.generate "molly-brown.toml" cfg.settings;
 in {
 
   options.services.molly-brown = {
@@ -76,7 +61,7 @@ in {
     };
 
     settings = mkOption {
-      type = settingsType;
+      inherit (settingsFormat) type;
       default = { };
       description = ''
         molly-brown configuration. Refer to
diff --git a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
index 0cb84de793e0..7fcd61880ea8 100644
--- a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
@@ -61,7 +61,6 @@ let
     proxy_set_header        X-Forwarded-Proto $scheme;
     proxy_set_header        X-Forwarded-Host $host;
     proxy_set_header        X-Forwarded-Server $host;
-    proxy_set_header        Accept-Encoding "";
   '';
 
   upstreamConfig = toString (flip mapAttrsToList cfg.upstreams (name: upstream: ''
@@ -114,7 +113,7 @@ let
       ''}
 
       ssl_protocols ${cfg.sslProtocols};
-      ssl_ciphers ${cfg.sslCiphers};
+      ${optionalString (cfg.sslCiphers != null) "ssl_ciphers ${cfg.sslCiphers};"}
       ${optionalString (cfg.sslDhparam != null) "ssl_dhparam ${cfg.sslDhparam};"}
 
       ${optionalString (cfg.recommendedTlsSettings) ''
@@ -289,10 +288,7 @@ let
             ssl_trusted_certificate ${vhost.sslTrustedCertificate};
           ''}
 
-          ${optionalString (vhost.basicAuthFile != null || vhost.basicAuth != {}) ''
-            auth_basic secured;
-            auth_basic_user_file ${if vhost.basicAuthFile != null then vhost.basicAuthFile else mkHtpasswd vhostName vhost.basicAuth};
-          ''}
+          ${mkBasicAuth vhostName vhost}
 
           ${mkLocations vhost.locations}
 
@@ -325,9 +321,19 @@ let
       ${optionalString (config.return != null) "return ${config.return};"}
       ${config.extraConfig}
       ${optionalString (config.proxyPass != null && cfg.recommendedProxySettings) "include ${recommendedProxyConfig};"}
+      ${mkBasicAuth "sublocation" config}
     }
   '') (sortProperties (mapAttrsToList (k: v: v // { location = k; }) locations)));
-  mkHtpasswd = vhostName: authDef: pkgs.writeText "${vhostName}.htpasswd" (
+
+  mkBasicAuth = name: zone: optionalString (zone.basicAuthFile != null || zone.basicAuth != {}) (let
+    auth_file = if zone.basicAuthFile != null
+      then zone.basicAuthFile
+      else mkHtpasswd name zone.basicAuth;
+  in ''
+    auth_basic secured;
+    auth_basic_user_file ${auth_file};
+  '');
+  mkHtpasswd = name: authDef: pkgs.writeText "${name}.htpasswd" (
     concatStringsSep "\n" (mapAttrsToList (user: password: ''
       ${user}:{PLAIN}${password}
     '') authDef)
@@ -415,13 +421,24 @@ in
       };
 
       config = mkOption {
+        type = types.str;
         default = "";
-        description = "
-          Verbatim nginx.conf configuration.
-          This is mutually exclusive with the structured configuration
-          via virtualHosts and the recommendedXyzSettings configuration
-          options. See appendConfig for appending to the generated http block.
-        ";
+        description = ''
+          Verbatim <filename>nginx.conf</filename> configuration.
+          This is mutually exclusive to any other config option for
+          <filename>nginx.conf</filename> except for
+          <itemizedlist>
+          <listitem><para><xref linkend="opt-services.nginx.appendConfig" />
+          </para></listitem>
+          <listitem><para><xref linkend="opt-services.nginx.httpConfig" />
+          </para></listitem>
+          <listitem><para><xref linkend="opt-services.nginx.logError" />
+          </para></listitem>
+          </itemizedlist>
+
+          If additional verbatim config in addition to other options is needed,
+          <xref linkend="opt-services.nginx.appendConfig" /> should be used instead.
+        '';
       };
 
       appendConfig = mkOption {
@@ -519,7 +536,7 @@ in
       };
 
       sslCiphers = mkOption {
-        type = types.str;
+        type = types.nullOr types.str;
         # Keep in sync with https://ssl-config.mozilla.org/#server=nginx&config=intermediate
         default = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
         description = "Ciphers to choose from when negotiating TLS handshakes.";
@@ -725,6 +742,8 @@ in
         ${cfg.preStart}
         ${execCommand} -t
       '';
+
+      startLimitIntervalSec = 60;
       serviceConfig = {
         ExecStart = execCommand;
         ExecReload = [
@@ -733,7 +752,6 @@ in
         ];
         Restart = "always";
         RestartSec = "10s";
-        StartLimitInterval = "1min";
         # User and group
         User = cfg.user;
         Group = cfg.group;
diff --git a/nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix b/nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix
index a85bacb9e4e2..5a7f5188b6cf 100644
--- a/nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix
@@ -9,6 +9,34 @@ with lib;
 
 {
   options = {
+    basicAuth = mkOption {
+      type = types.attrsOf types.str;
+      default = {};
+      example = literalExample ''
+        {
+          user = "password";
+        };
+      '';
+      description = ''
+        Basic Auth protection for a vhost.
+
+        WARNING: This is implemented to store the password in plain text in the
+        Nix store.
+      '';
+    };
+
+    basicAuthFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        Basic Auth password file for a vhost.
+        Can be created via: <command>htpasswd -c &lt;filename&gt; &lt;username&gt;</command>.
+
+        WARNING: The generate file contains the users' passwords in a
+        non-cryptographically-securely hashed way.
+      '';
+    };
+
     proxyPass = mkOption {
       type = types.nullOr types.str;
       default = null;
diff --git a/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix
index 455854e2a965..cf211ea9a71b 100644
--- a/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix
@@ -198,7 +198,7 @@ with lib;
         Basic Auth protection for a vhost.
 
         WARNING: This is implemented to store the password in plain text in the
-        nix store.
+        Nix store.
       '';
     };
 
@@ -207,7 +207,10 @@ with lib;
       default = null;
       description = ''
         Basic Auth password file for a vhost.
-        Can be created via: <command>htpasswd -c &lt;filename&gt; &lt;username&gt;</command>
+        Can be created via: <command>htpasswd -c &lt;filename&gt; &lt;username&gt;</command>.
+
+        WARNING: The generate file contains the users' passwords in a
+        non-cryptographically-securely hashed way.
       '';
     };
 
diff --git a/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix b/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix
index 759eebf768db..4d302299f5f0 100644
--- a/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix
@@ -26,12 +26,9 @@ let
   phpIni = poolOpts: pkgs.runCommand "php.ini" {
     inherit (poolOpts) phpPackage phpOptions;
     preferLocalBuild = true;
-    nixDefaults = ''
-      sendmail_path = "/run/wrappers/bin/sendmail -t -i"
-    '';
-    passAsFile = [ "nixDefaults" "phpOptions" ];
+    passAsFile = [ "phpOptions" ];
   } ''
-    cat ${poolOpts.phpPackage}/etc/php.ini $nixDefaultsPath $phpOptionsPath > $out
+    cat ${poolOpts.phpPackage}/etc/php.ini $phpOptionsPath > $out
   '';
 
   poolOpts = { name, ... }:
diff --git a/nixpkgs/nixos/modules/services/web-servers/traefik.nix b/nixpkgs/nixos/modules/services/web-servers/traefik.nix
index 4ab7307c3b67..3d29199dd454 100644
--- a/nixpkgs/nixos/modules/services/web-servers/traefik.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/traefik.nix
@@ -136,6 +136,8 @@ in {
       description = "Traefik web server";
       after = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
+      startLimitIntervalSec = 86400;
+      startLimitBurst = 5;
       serviceConfig = {
         ExecStart =
           "${cfg.package}/bin/traefik --configfile=${staticConfigFile}";
@@ -143,8 +145,6 @@ in {
         User = "traefik";
         Group = cfg.group;
         Restart = "on-failure";
-        StartLimitInterval = 86400;
-        StartLimitBurst = 5;
         AmbientCapabilities = "cap_net_bind_service";
         CapabilityBoundingSet = "cap_net_bind_service";
         NoNewPrivileges = true;
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 69cf98321720..68a65d77d62f 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -17,6 +17,11 @@ let
     '';
   };
 
+  defaultFavoriteAppsOverride = ''
+    [org.gnome.shell]
+    favorite-apps=[ 'org.gnome.Geary.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Photos.desktop', 'org.gnome.Nautilus.desktop' ]
+  '';
+
   nixos-gsettings-desktop-schemas = let
     defaultPackages = with pkgs; [ gsettings-desktop-schemas gnome3.gnome-shell ];
   in
@@ -42,8 +47,7 @@ let
        [org.gnome.desktop.screensaver]
        picture-uri='file://${pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom.gnomeFilePath}'
 
-       [org.gnome.shell]
-       favorite-apps=[ 'org.gnome.Epiphany.desktop', 'org.gnome.Geary.desktop', 'org.gnome.Music.desktop', 'org.gnome.Photos.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]
+       ${cfg.favoriteAppsOverride}
 
        ${cfg.extraGSettingsOverrides}
      EOF
@@ -53,6 +57,8 @@ let
 
   flashbackEnabled = cfg.flashback.enableMetacity || length cfg.flashback.customSessions > 0;
 
+  notExcluded = pkg: mkDefault (!(lib.elem pkg config.environment.gnome3.excludePackages));
+
 in
 
 {
@@ -67,7 +73,40 @@ in
       core-os-services.enable = mkEnableOption "essential services for GNOME3";
       core-shell.enable = mkEnableOption "GNOME Shell services";
       core-utilities.enable = mkEnableOption "GNOME core utilities";
+      core-developer-tools.enable = mkEnableOption "GNOME core developer tools";
       games.enable = mkEnableOption "GNOME games";
+
+      experimental-features = {
+        realtime-scheduling = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Makes mutter (which propagates to gnome-shell) request a low priority real-time
+            scheduling which is only available on the wayland session.
+            To enable this experimental feature it requires a restart of the compositor.
+            Note that enabling this option only enables the <emphasis>capability</emphasis>
+            for realtime-scheduling to be used. It doesn't automatically set the gsetting
+            so that mutter actually uses realtime-scheduling. This would require adding <literal>
+            rt-scheduler</literal> to <literal>/org/gnome/mutter/experimental-features</literal>
+            with dconf-editor. You cannot use extraGSettingsOverrides because that will only
+            change the default value of the setting.
+
+            Please be aware of these known issues with the feature in nixos:
+            <itemizedlist>
+             <listitem>
+              <para>
+               <link xlink:href="https://github.com/NixOS/nixpkgs/issues/90201">NixOS/nixpkgs#90201</link>
+              </para>
+             </listitem>
+             <listitem>
+              <para>
+               <link xlink:href="https://github.com/NixOS/nixpkgs/issues/86730">NixOS/nixpkgs#86730</link>
+              </para>
+            </listitem>
+            </itemizedlist>
+          '';
+        };
+      };
     };
 
     services.xserver.desktopManager.gnome3 = {
@@ -89,6 +128,17 @@ in
         apply = list: list ++ [ pkgs.gnome3.gnome-shell pkgs.gnome3.gnome-shell-extensions ];
       };
 
+      favoriteAppsOverride = mkOption {
+        internal = true; # this is messy
+        default = defaultFavoriteAppsOverride;
+        type = types.lines;
+        example = literalExample ''
+          [org.gnome.shell]
+          favorite-apps=[ 'firefox.desktop', 'org.gnome.Calendar.desktop' ]
+        '';
+        description = "List of desktop files to put as favorite apps into gnome-shell. These need to be installed somehow globally.";
+      };
+
       extraGSettingsOverrides = mkOption {
         default = "";
         type = types.lines;
@@ -145,6 +195,14 @@ in
 
   config = mkMerge [
     (mkIf (cfg.enable || flashbackEnabled) {
+      # Seed our configuration into nixos-generate-config
+      system.nixos-generate-config.desktopConfiguration = ''
+        # Enable the GNOME 3 Desktop Environment.
+        services.xserver.enable = true;
+        services.xserver.displayManager.gdm.enable = true;
+        services.xserver.desktopManager.gnome3.enable = true;
+      '';
+
       services.gnome3.core-os-services.enable = true;
       services.gnome3.core-shell.enable = true;
       services.gnome3.core-utilities.enable = mkDefault true;
@@ -173,6 +231,11 @@ in
 
        # If gnome3 is installed, build vim for gtk3 too.
       nixpkgs.config.vim.gui = "gtk3";
+
+      # Install gnome-software if flatpak is enabled
+      services.flatpak.guiPackages = [
+        pkgs.gnome3.gnome-software
+      ];
     })
 
     (mkIf flashbackEnabled {
@@ -260,6 +323,12 @@ in
         gnome-shell
       ];
 
+      services.udev.packages = with pkgs.gnome3; [
+        # Force enable KMS modifiers for devices that require them.
+        # https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1443
+        mutter
+      ];
+
       services.avahi.enable = mkDefault true;
 
       xdg.portal.extraPortals = [
@@ -289,27 +358,7 @@ in
         source-sans-pro
       ];
 
-      ## Enable soft realtime scheduling, only supported on wayland ##
-
-      security.wrappers.".gnome-shell-wrapped" = {
-        source = "${pkgs.gnome3.gnome-shell}/bin/.gnome-shell-wrapped";
-        capabilities = "cap_sys_nice=ep";
-      };
-
-      systemd.user.services.gnome-shell-wayland = let
-        gnomeShellRT = with pkgs.gnome3; pkgs.runCommand "gnome-shell-rt" {} ''
-          mkdir -p $out/bin/
-          cp ${gnome-shell}/bin/gnome-shell $out/bin
-          sed -i "s@${gnome-shell}/bin/@${config.security.wrapperDir}/@" $out/bin/gnome-shell
-        '';
-      in {
-        # Note we need to clear ExecStart before overriding it
-        serviceConfig.ExecStart = ["" "${gnomeShellRT}/bin/gnome-shell"];
-        # Do not use the default environment, it provides a broken PATH
-        environment = mkForce {};
-      };
-
-      # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-36/elements/core/meta-gnome-core-shell.bst
+      # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-shell.bst
       environment.systemPackages = with pkgs.gnome3; [
         adwaita-icon-theme
         gnome-backgrounds
@@ -333,13 +382,36 @@ in
       ];
     })
 
-    # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-36/elements/core/meta-gnome-core-utilities.bst
+    # Enable soft realtime scheduling, only supported on wayland
+    (mkIf serviceCfg.experimental-features.realtime-scheduling {
+      security.wrappers.".gnome-shell-wrapped" = {
+        source = "${pkgs.gnome3.gnome-shell}/bin/.gnome-shell-wrapped";
+        capabilities = "cap_sys_nice=ep";
+      };
+
+      systemd.user.services.gnome-shell-wayland = let
+        gnomeShellRT = with pkgs.gnome3; pkgs.runCommand "gnome-shell-rt" {} ''
+          mkdir -p $out/bin/
+          cp ${gnome-shell}/bin/gnome-shell $out/bin
+          sed -i "s@${gnome-shell}/bin/@${config.security.wrapperDir}/@" $out/bin/gnome-shell
+        '';
+      in {
+        # Note we need to clear ExecStart before overriding it
+        serviceConfig.ExecStart = ["" "${gnomeShellRT}/bin/gnome-shell"];
+        # Do not use the default environment, it provides a broken PATH
+        environment = mkForce {};
+      };
+    })
+
+    # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-utilities.bst
     (mkIf serviceCfg.core-utilities.enable {
       environment.systemPackages = (with pkgs.gnome3; removePackagesByName [
         baobab
         cheese
         eog
-        epiphany
+        /* Not in good standing on nixos:
+         * https://github.com/NixOS/nixpkgs/issues/98819
+        /* epiphany */
         gedit
         gnome-calculator
         gnome-calendar
@@ -350,27 +422,28 @@ in
         gnome-logs
         gnome-maps
         gnome-music
-        gnome-photos
+        pkgs.gnome-photos
         gnome-screenshot
-        gnome-software
         gnome-system-monitor
         gnome-weather
         nautilus
+        pkgs.gnome-connections
         simple-scan
         totem
         yelp
-        # Unsure if sensible for NixOS
-        /* gnome-boxes */
       ] config.environment.gnome3.excludePackages);
 
-      # Enable default programs
-      programs.evince.enable = mkDefault true;
-      programs.file-roller.enable = mkDefault true;
-      programs.geary.enable = mkDefault true;
-      programs.gnome-disks.enable = mkDefault true;
-      programs.gnome-terminal.enable = mkDefault true;
-      programs.seahorse.enable = mkDefault true;
-      services.gnome3.sushi.enable = mkDefault true;
+      # Enable default program modules
+      # Since some of these have a corresponding package, we only
+      # enable that program module if the package hasn't been excluded
+      # through `environment.gnome3.excludePackages`
+      programs.evince.enable = notExcluded pkgs.gnome3.evince;
+      programs.file-roller.enable = notExcluded pkgs.gnome3.file-roller;
+      programs.geary.enable = notExcluded pkgs.gnome3.geary;
+      programs.gnome-disks.enable = notExcluded pkgs.gnome3.gnome-disk-utility;
+      programs.gnome-terminal.enable = notExcluded pkgs.gnome3.gnome-terminal;
+      programs.seahorse.enable = notExcluded pkgs.gnome3.seahorse;
+      services.gnome3.sushi.enable = notExcluded pkgs.gnome3.sushi;
 
       # Let nautilus find extensions
       # TODO: Create nautilus-with-extensions package
@@ -386,12 +459,43 @@ in
 
     (mkIf serviceCfg.games.enable {
       environment.systemPackages = (with pkgs.gnome3; removePackagesByName [
-        aisleriot atomix five-or-more four-in-a-row gnome-chess gnome-klotski
-        gnome-mahjongg gnome-mines gnome-nibbles gnome-robots gnome-sudoku
-        gnome-taquin gnome-tetravex hitori iagno lightsoff quadrapassel
-        swell-foop tali
+        aisleriot
+        atomix
+        five-or-more
+        four-in-a-row
+        gnome-chess
+        gnome-klotski
+        gnome-mahjongg
+        gnome-mines
+        gnome-nibbles
+        gnome-robots
+        gnome-sudoku
+        gnome-taquin
+        gnome-tetravex
+        hitori
+        iagno
+        lightsoff
+        quadrapassel
+        swell-foop
+        tali
       ] config.environment.gnome3.excludePackages);
     })
+
+    # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/3.38.0/elements/core/meta-gnome-core-developer-tools.bst
+    (mkIf serviceCfg.core-developer-tools.enable {
+      environment.systemPackages = (with pkgs.gnome3; removePackagesByName [
+        dconf-editor
+        devhelp
+        pkgs.gnome-builder
+        # boxes would make sense in this option, however
+        # it doesn't function well enough to be included
+        # in default configurations.
+        # https://github.com/NixOS/nixpkgs/issues/60908
+        /* gnome-boxes */
+      ] config.environment.gnome3.excludePackages);
+
+      services.sysprof.enable = true;
+    })
   ];
 
 }
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix
index e67e216f90d9..cf02a71248b1 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -180,7 +180,6 @@ in
         gtk3.out
         hicolor-icon-theme
         lightlocker
-        nixos-artwork.wallpapers.simple-dark-gray
         onboard
         qgnomeplatform
         shared-mime-info
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 149f6cbb7628..5f1c099c283d 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -8,8 +8,7 @@ let
   cfg = xcfg.desktopManager.plasma5;
 
   inherit (pkgs) kdeApplications kdeFrameworks plasma5;
-  libsForQt5 = pkgs.libsForQt514;
-  qt5 = pkgs.qt514;
+  inherit (pkgs) qt5 libsForQt5;
   inherit (pkgs) writeText;
 
   pulseaudio = config.hardware.pulseaudio;
@@ -184,6 +183,14 @@ in
 
   config = mkMerge [
     (mkIf cfg.enable {
+      # Seed our configuration into nixos-generate-config
+      system.nixos-generate-config.desktopConfiguration = ''
+        # Enable the Plasma 5 Desktop Environment.
+        services.xserver.enable = true;
+        services.xserver.displayManager.sddm.enable = true;
+        services.xserver.desktopManager.plasma5.enable = true;
+      '';
+
       services.xserver.desktopManager.session = singleton {
         name = "plasma5";
         bgSupport = true;
@@ -192,7 +199,7 @@ in
 
       security.wrappers = {
         kcheckpass.source = "${lib.getBin plasma5.kscreenlocker}/libexec/kcheckpass";
-        start_kdeinit.source = "${lib.getBin pkgs.kinit}/libexec/kf5/start_kdeinit";
+        start_kdeinit.source = "${lib.getBin pkgs.kdeFrameworks.kinit}/libexec/kf5/start_kdeinit";
         kwin_wayland = {
           source = "${lib.getBin plasma5.kwin}/bin/kwin_wayland";
           capabilities = "cap_sys_nice+ep";
@@ -230,6 +237,7 @@ in
           kidletime
           kimageformats
           kinit
+          kirigami2  # In system profile for SDDM theme. TODO: wrapper.
           kio
           kjobwidgets
           knewstuff
@@ -274,6 +282,7 @@ in
           plasma-browser-integration
           plasma-integration
           polkit-kde-agent
+          spectacle
           systemsettings
 
           plasma-desktop
@@ -358,10 +367,12 @@ in
       security.pam.services.sddm.enableKwallet = true;
 
       xdg.portal.enable = true;
-      xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-kde ];
+      xdg.portal.extraPortals = [ plasma5.xdg-desktop-portal-kde ];
 
       # Update the start menu for each user that is currently logged in
       system.userActivationScripts.plasmaSetup = activationScript;
+
+      nixpkgs.config.firefox.enablePlasmaBrowserIntegration = true;
     })
   ];
 
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/default.nix b/nixpkgs/nixos/modules/services/x11/display-managers/default.nix
index 08ce8edd6612..6945a241f92f 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/default.nix
@@ -37,13 +37,6 @@ let
       . /etc/profile
       cd "$HOME"
 
-      ${optionalString cfg.startDbusSession ''
-        if test -z "$DBUS_SESSION_BUS_ADDRESS"; then
-          /run/current-system/systemd/bin/systemctl --user start dbus.socket
-          export `/run/current-system/systemd/bin/systemctl --user show-environment | grep '^DBUS_SESSION_BUS_ADDRESS'`
-        fi
-      ''}
-
       ${optionalString cfg.displayManager.job.logToJournal ''
         if [ -z "$_DID_SYSTEMD_CAT" ]; then
           export _DID_SYSTEMD_CAT=1
@@ -481,6 +474,12 @@ in
             )
             [dms wms]
           );
+
+    # Make xsessions and wayland sessions available in XDG_DATA_DIRS
+    # as some programs have behavior that depends on them being present
+    environment.sessionVariables.XDG_DATA_DIRS = [
+      "${cfg.displayManager.sessionData.desktops}/share"
+    ];
   };
 
   imports = [
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
index eae70a57c781..e3c5adb9737f 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
@@ -160,7 +160,7 @@ in
     ];
 
     # Otherwise GDM will not be able to start correctly and display Wayland sessions
-    systemd.packages = with pkgs.gnome3; [ gnome-session gnome-shell ];
+    systemd.packages = with pkgs.gnome3; [ gdm gnome-session gnome-shell ];
     environment.systemPackages = [ pkgs.gnome3.adwaita-icon-theme ];
 
     systemd.services.display-manager.wants = [
@@ -264,7 +264,7 @@ in
     # presented and there's a little delay.
     environment.etc."gdm/custom.conf".text = ''
       [daemon]
-      WaylandEnable=${if cfg.gdm.wayland then "true" else "false"}
+      WaylandEnable=${boolToString cfg.gdm.wayland}
       ${optionalString cfg.autoLogin.enable (
         if cfg.gdm.autoLogin.delay > 0 then ''
           TimedLoginEnable=true
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix
index 143785db0b4f..2dafee9e36e3 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -308,6 +308,7 @@ in
       home = "/var/lib/lightdm";
       group = "lightdm";
       uid = config.ids.uids.lightdm;
+      shell = pkgs.bash;
     };
 
     systemd.tmpfiles.rules = [
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix
index e63bb2e44539..116994db1c14 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix
@@ -1,97 +1,94 @@
 { config, lib, pkgs, ... }:
 
 with lib;
-
 let
-
   xcfg = config.services.xserver;
   dmcfg = xcfg.displayManager;
   cfg = dmcfg.sddm;
   xEnv = config.systemd.services.display-manager.environment;
 
-  inherit (pkgs) sddm;
+  sddm = pkgs.libsForQt5.sddm;
+
+  iniFmt = pkgs.formats.ini { };
 
-  xserverWrapper = pkgs.writeScript "xserver-wrapper" ''
-    #!/bin/sh
+  xserverWrapper = pkgs.writeShellScript "xserver-wrapper" ''
     ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
     exec systemd-cat -t xserver-wrapper ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} "$@"
   '';
 
-  Xsetup = pkgs.writeScript "Xsetup" ''
-    #!/bin/sh
+  Xsetup = pkgs.writeShellScript "Xsetup" ''
     ${cfg.setupScript}
     ${dmcfg.setupCommands}
   '';
 
-  Xstop = pkgs.writeScript "Xstop" ''
-    #!/bin/sh
+  Xstop = pkgs.writeShellScript "Xstop" ''
     ${cfg.stopScript}
   '';
 
-  cfgFile = pkgs.writeText "sddm.conf" ''
-    [General]
-    HaltCommand=/run/current-system/systemd/bin/systemctl poweroff
-    RebootCommand=/run/current-system/systemd/bin/systemctl reboot
-    ${optionalString cfg.autoNumlock ''
-    Numlock=on
-    ''}
-
-    [Theme]
-    Current=${cfg.theme}
-    ThemeDir=/run/current-system/sw/share/sddm/themes
-    FacesDir=/run/current-system/sw/share/sddm/faces
-
-    [Users]
-    MaximumUid=${toString config.ids.uids.nixbld}
-    HideUsers=${concatStringsSep "," dmcfg.hiddenUsers}
-    HideShells=/run/current-system/sw/bin/nologin
-
-    [X11]
-    MinimumVT=${toString (if xcfg.tty != null then xcfg.tty else 7)}
-    ServerPath=${xserverWrapper}
-    XephyrPath=${pkgs.xorg.xorgserver.out}/bin/Xephyr
-    SessionCommand=${dmcfg.sessionData.wrapper}
-    SessionDir=${dmcfg.sessionData.desktops}/share/xsessions
-    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"}
-    SessionDir=${dmcfg.sessionData.desktops}/share/wayland-sessions
-
-    ${optionalString dmcfg.autoLogin.enable ''
-    [Autologin]
-    User=${dmcfg.autoLogin.user}
-    Session=${autoLoginSessionName}.desktop
-    Relogin=${boolToString cfg.autoLogin.relogin}
-    ''}
-
-    ${cfg.extraConfig}
-  '';
+  defaultConfig = {
+    General = {
+      HaltCommand = "/run/current-system/systemd/bin/systemctl poweroff";
+      RebootCommand = "/run/current-system/systemd/bin/systemctl reboot";
+      Numlock = if cfg.autoNumlock then "on" else "none"; # on, off none
+    };
+
+    Theme = {
+      Current = cfg.theme;
+      ThemeDir = "/run/current-system/sw/share/sddm/themes";
+      FacesDir = "/run/current-system/sw/share/sddm/faces";
+    };
+
+    Users = {
+      MaximumUid = config.ids.uids.nixbld;
+      HideUsers = concatStringsSep "," dmcfg.hiddenUsers;
+      HideShells = "/run/current-system/sw/bin/nologin";
+    };
 
-  autoLoginSessionName = dmcfg.sessionData.autologinSession;
+    X11 = {
+      MinimumVT = if xcfg.tty != null then xcfg.tty else 7;
+      ServerPath = toString xserverWrapper;
+      XephyrPath = "${pkgs.xorg.xorgserver.out}/bin/Xephyr";
+      SessionCommand = toString dmcfg.sessionData.wrapper;
+      SessionDir = "${dmcfg.sessionData.desktops}/share/xsessions";
+      XauthPath = "${pkgs.xorg.xauth}/bin/xauth";
+      DisplayCommand = toString Xsetup;
+      DisplayStopCommand = toString Xstop;
+      EnableHiDPI = cfg.enableHidpi;
+    };
+
+    Wayland = {
+      EnableHiDPI = cfg.enableHidpi;
+      SessionDir = "${dmcfg.sessionData.desktops}/share/wayland-sessions";
+    };
+  } // lib.optionalAttrs dmcfg.autoLogin.enable {
+    Autologin = {
+      User = dmcfg.autoLogin.user;
+      Session = autoLoginSessionName;
+      Relogin = cfg.autoLogin.relogin;
+    };
+  };
+
+  cfgFile =
+    iniFmt.generate "sddm.conf" (lib.recursiveUpdate defaultConfig cfg.settings);
+
+  autoLoginSessionName =
+    "${dmcfg.sessionData.autologinSession}.desktop";
 
 in
 {
   imports = [
-    (mkRemovedOptionModule [ "services" "xserver" "displayManager" "sddm" "themes" ]
+    (mkRemovedOptionModule
+      [ "services" "xserver" "displayManager" "sddm" "themes" ]
       "Set the option `services.xserver.displayManager.sddm.package' instead.")
-    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "autoLogin" "enable" ] [
-      "services"
-      "xserver"
-      "displayManager"
-      "autoLogin"
-      "enable"
-    ])
-    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "sddm" "autoLogin" "user" ] [
-      "services"
-      "xserver"
-      "displayManager"
-      "autoLogin"
-      "user"
-    ])
+    (mkRenamedOptionModule
+      [ "services" "xserver" "displayManager" "sddm" "autoLogin" "enable" ]
+      [ "services" "xserver" "displayManager" "autoLogin" "enable" ])
+    (mkRenamedOptionModule
+      [ "services" "xserver" "displayManager" "sddm" "autoLogin" "user" ]
+      [ "services" "xserver" "displayManager" "autoLogin" "user" ])
+    (mkRemovedOptionModule
+      [ "services" "xserver" "displayManager" "sddm" "extraConfig" ]
+      "Set the option `services.xserver.displayManager.sddm.settings' instead.")
   ];
 
   options = {
@@ -110,22 +107,22 @@ in
         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 = "";
+      settings = mkOption {
+        type = iniFmt.type;
+        default = { };
         example = ''
-          [Autologin]
-          User=john
-          Session=plasma.desktop
+          {
+            Autologin = {
+              User = "john";
+              Session = "plasma.desktop";
+            };
+          }
         '';
         description = ''
-          Extra lines appended to the configuration of SDDM.
+          Extra settings merged in and overwritting defaults in sddm.conf.
         '';
       };
 
@@ -168,28 +165,38 @@ in
       };
 
       # Configuration for automatic login specific to SDDM
-      autoLogin.relogin = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          If true automatic login will kick in again on session exit (logout), otherwise it
-          will only log in automatically when the display-manager is started.
-        '';
+      autoLogin = {
+        relogin = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            If true automatic login will kick in again on session exit (logout), otherwise it
+            will only log in automatically when the display-manager is started.
+          '';
+        };
+
+        minimumUid = mkOption {
+          type = types.ints.u16;
+          default = 1000;
+          description = ''
+            Minimum user ID for auto-login user.
+          '';
+        };
       };
-
     };
-
   };
 
   config = mkIf cfg.enable {
 
     assertions = [
-      { assertion = xcfg.enable;
+      {
+        assertion = xcfg.enable;
         message = ''
           SDDM requires services.xserver.enable to be true
         '';
       }
-      { assertion = dmcfg.autoLogin.enable -> autoLoginSessionName != null;
+      {
+        assertion = dmcfg.autoLogin.enable -> autoLoginSessionName != null;
         message = ''
           SDDM auto-login requires that services.xserver.displayManager.defaultSession is set.
         '';
@@ -230,7 +237,7 @@ in
 
       sddm-autologin.text = ''
         auth     requisite pam_nologin.so
-        auth     required  pam_succeed_if.so uid >= 1000 quiet
+        auth     required  pam_succeed_if.so uid >= ${toString cfg.autoLogin.minimumUid} quiet
         auth     required  pam_permit.so
 
         account  include   sddm
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix b/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix
index 3980203b9457..6cd46cdf9649 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix
@@ -39,6 +39,18 @@ in
       displayManager.lightdm.enable = lib.mkForce false;
     };
     systemd.services.display-manager.enable = false;
+
+    # Other displayManagers log to /dev/null because they're services and put
+    # Xorg's stdout in the journal
+    #
+    # To send log to Xorg's default log location ($XDG_DATA_HOME/xorg/), we do
+    # not specify a log file when running X
+    services.xserver.logFile = mkDefault null;
+
+    # Implement xserverArgs via xinit's system-wide xserverrc
+    environment.etc."X11/xinit/xserverrc".source = pkgs.writeShellScript "xserverrc" ''
+      exec ${pkgs.xorg.xorgserver}/bin/X ${toString config.services.xserver.displayManager.xserverArgs} "$@"
+    '';
     environment.systemPackages =  with pkgs; [ xorg.xinit ];
   };
 
diff --git a/nixpkgs/nixos/modules/services/x11/redshift.nix b/nixpkgs/nixos/modules/services/x11/redshift.nix
index 21b0b33553ac..60d80a28762b 100644
--- a/nixpkgs/nixos/modules/services/x11/redshift.nix
+++ b/nixpkgs/nixos/modules/services/x11/redshift.nix
@@ -82,6 +82,15 @@ in {
       '';
     };
 
+    executable = mkOption {
+      type = types.str;
+      default = "/bin/redshift";
+      example = "/bin/redshift-gtk";
+      description = ''
+        Redshift executable to use within the package.
+      '';
+    };
+
     extraOptions = mkOption {
       type = types.listOf types.str;
       default = [];
@@ -114,7 +123,7 @@ in {
       partOf = [ "graphical-session.target" ];
       serviceConfig = {
         ExecStart = ''
-          ${cfg.package}/bin/redshift \
+          ${cfg.package}${cfg.executable} \
             -l ${providerString} \
             -t ${toString cfg.temperature.day}:${toString cfg.temperature.night} \
             -b ${toString cfg.brightness.day}:${toString cfg.brightness.night} \
diff --git a/nixpkgs/nixos/modules/services/x11/terminal-server.nix b/nixpkgs/nixos/modules/services/x11/terminal-server.nix
index 503c14c9b624..e6b50c21a952 100644
--- a/nixpkgs/nixos/modules/services/x11/terminal-server.nix
+++ b/nixpkgs/nixos/modules/services/x11/terminal-server.nix
@@ -32,7 +32,7 @@ with lib;
 
         path =
           [ pkgs.xorg.xorgserver.out pkgs.gawk pkgs.which pkgs.openssl pkgs.xorg.xauth
-            pkgs.nettools pkgs.shadow pkgs.procps pkgs.utillinux pkgs.bash
+            pkgs.nettools pkgs.shadow pkgs.procps pkgs.util-linux pkgs.bash
           ];
 
         environment.FD_GEOM = "1024x786x24";
diff --git a/nixpkgs/nixos/modules/services/x11/window-managers/evilwm.nix b/nixpkgs/nixos/modules/services/x11/window-managers/evilwm.nix
index 6e19e3572c79..6f1db2110f87 100644
--- a/nixpkgs/nixos/modules/services/x11/window-managers/evilwm.nix
+++ b/nixpkgs/nixos/modules/services/x11/window-managers/evilwm.nix
@@ -16,8 +16,8 @@ in
     services.xserver.windowManager.session = singleton {
       name = "evilwm";
       start = ''
-	${pkgs.evilwm}/bin/evilwm &
-	waitPID=$!
+        ${pkgs.evilwm}/bin/evilwm &
+        waitPID=$!
       '';
     };
     environment.systemPackages = [ pkgs.evilwm ];
diff --git a/nixpkgs/nixos/modules/services/x11/window-managers/exwm.nix b/nixpkgs/nixos/modules/services/x11/window-managers/exwm.nix
index dc1d957c1709..88e13f4dbfb0 100644
--- a/nixpkgs/nixos/modules/services/x11/window-managers/exwm.nix
+++ b/nixpkgs/nixos/modules/services/x11/window-managers/exwm.nix
@@ -5,7 +5,7 @@ with lib;
 let
   cfg = config.services.xserver.windowManager.exwm;
   loadScript = pkgs.writeText "emacs-exwm-load" ''
-    (require 'exwm)
+    ${cfg.loadScript}
     ${optionalString cfg.enableDefaultConfig ''
       (require 'exwm-config)
       (exwm-config-default)
@@ -19,6 +19,18 @@ in
   options = {
     services.xserver.windowManager.exwm = {
       enable = mkEnableOption "exwm";
+      loadScript = mkOption {
+        default = "(require 'exwm)";
+        example = literalExample ''
+          (require 'exwm)
+          (exwm-enable)
+        '';
+        description = ''
+          Emacs lisp code to be run after loading the user's init
+          file. If enableDefaultConfig is true, this will be run
+          before loading the default config.
+        '';
+      };
       enableDefaultConfig = mkOption {
         default = true;
         type = lib.types.bool;
diff --git a/nixpkgs/nixos/modules/services/x11/window-managers/xmonad.nix b/nixpkgs/nixos/modules/services/x11/window-managers/xmonad.nix
index dba25da8260c..2bb4827be9d5 100644
--- a/nixpkgs/nixos/modules/services/x11/window-managers/xmonad.nix
+++ b/nixpkgs/nixos/modules/services/x11/window-managers/xmonad.nix
@@ -4,23 +4,39 @@ with lib;
 let
   inherit (lib) mkOption mkIf optionals literalExample;
   cfg = config.services.xserver.windowManager.xmonad;
-  xmonad = pkgs.xmonad-with-packages.override {
-    ghcWithPackages = cfg.haskellPackages.ghcWithPackages;
-    packages = self: cfg.extraPackages self ++
-                     optionals cfg.enableContribAndExtras
-                     [ self.xmonad-contrib self.xmonad-extras ];
+
+  ghcWithPackages = cfg.haskellPackages.ghcWithPackages;
+  packages = self: cfg.extraPackages self ++
+                   optionals cfg.enableContribAndExtras
+                   [ self.xmonad-contrib self.xmonad-extras ];
+
+  xmonad-vanilla = pkgs.xmonad-with-packages.override {
+    inherit ghcWithPackages packages;
   };
-  xmonadBin = pkgs.writers.writeHaskell "xmonad" {
-    ghc = cfg.haskellPackages.ghc;
-    libraries = [ cfg.haskellPackages.xmonad ] ++
-                cfg.extraPackages cfg.haskellPackages ++
-                optionals cfg.enableContribAndExtras
-                (with cfg.haskellPackages; [ xmonad-contrib xmonad-extras ]);
-    inherit (cfg) ghcArgs;
-  } cfg.config;
-
-in
-{
+
+  xmonad-config =
+    let
+      xmonadAndPackages = self: [ self.xmonad ] ++ packages self;
+      xmonadEnv = ghcWithPackages xmonadAndPackages;
+      configured = pkgs.writers.writeHaskellBin "xmonad" {
+        ghc = cfg.haskellPackages.ghc;
+        libraries = xmonadAndPackages cfg.haskellPackages;
+        inherit (cfg) ghcArgs;
+      } cfg.config;
+    in
+      pkgs.runCommandLocal "xmonad" {
+        nativeBuildInputs = [ pkgs.makeWrapper ];
+      } ''
+        install -D ${xmonadEnv}/share/man/man1/xmonad.1.gz $out/share/man/man1/xmonad.1.gz
+        makeWrapper ${configured}/bin/xmonad $out/bin/xmonad \
+          --set NIX_GHC "${xmonadEnv}/bin/ghc" \
+          --set XMONAD_XMESSAGE "${pkgs.xorg.xmessage}/bin/xmessage"
+      '';
+
+  xmonad = if (cfg.config != null) then xmonad-config else xmonad-vanilla;
+in {
+  meta.maintainers = with maintainers; [ lassulus xaverdh ivanbrennan ];
+
   options = {
     services.xserver.windowManager.xmonad = {
       enable = mkEnableOption "xmonad";
@@ -62,19 +78,56 @@ in
         default = null;
         type = with lib.types; nullOr (either path str);
         description = ''
-          Configuration from which XMonad gets compiled. If no value
-          is specified, the xmonad config from $HOME/.xmonad is taken.
-          If you use xmonad --recompile, $HOME/.xmonad will be taken as
-          the configuration, but on the next restart of display-manager
-          this config will be reapplied.
+          Configuration from which XMonad gets compiled. If no value is
+          specified, a vanilla xmonad binary is put in PATH, which will
+          attempt to recompile and exec your xmonad config from $HOME/.xmonad.
+          This setup is then analogous to other (non-NixOS) linux distributions.
+
+          If you do set this option, you likely want to use "launch" as your
+          entry point for xmonad (as in the example), to avoid xmonad's
+          recompilation logic on startup. Doing so will render the default
+          "mod+q" restart key binding dysfunctional though, because that attempts
+          to call your binary with the "--restart" command line option, unless
+          you implement that yourself. You way mant to bind "mod+q" to
+          <literal>(restart "xmonad" True)</literal> instead, which will just restart
+          xmonad from PATH. This allows e.g. switching to the new xmonad binary
+          after rebuilding your system with nixos-rebuild.
+
+          If you actually want to run xmonad with a config specified here, but
+          also be able to recompile and restart it from a copy of that source in
+          $HOME/.xmonad on the fly, you will have to implement that yourself
+          using something like "compileRestart" from the example.
+          This should allow you to switch at will between the local xmonad and
+          the one NixOS puts in your PATH.
         '';
         example = ''
           import XMonad
+          import XMonad.Util.EZConfig (additionalKeys)
+          import Control.Monad (when)
+          import Text.Printf (printf)
+          import System.Posix.Process (executeFile)
+          import System.Info (arch,os)
+          import System.Environment (getArgs)
+          import System.FilePath ((</>))
+
+          compiledConfig = printf "xmonad-%s-%s" arch os
+
+          compileRestart resume =
+            whenX (recompile True) $
+              when resume writeStateToFile
+                *> catchIO
+                  ( do
+                      dir <- getXMonadDataDir
+                      args <- getArgs
+                      executeFile (dir </> compiledConfig) False args Nothing
+                  )
 
           main = launch defaultConfig
-                 { modMask = mod4Mask -- Use Super instead of Alt
-                 , terminal = "urxvt"
-                 }
+              { modMask = mod4Mask -- Use Super instead of Alt
+              , terminal = "urxvt" }
+              `additionalKeys`
+              [ ( (mod4Mask,xK_r), compileRestart True)
+              , ( (mod4Mask,xK_q), restart "xmonad" True ) ]
         '';
       };
 
@@ -101,10 +154,8 @@ in
     services.xserver.windowManager = {
       session = [{
         name = "xmonad";
-        start = let
-          xmonadCommand = if (cfg.config != null) then xmonadBin else "${xmonad}/bin/xmonad";
-        in ''
-           systemd-cat -t xmonad -- ${xmonadCommand} ${lib.escapeShellArgs cfg.xmonadCliArgs} &
+        start = ''
+           systemd-cat -t xmonad -- ${xmonad}/bin/xmonad ${lib.escapeShellArgs cfg.xmonadCliArgs} &
            waitPID=$!
         '';
       }];
diff --git a/nixpkgs/nixos/modules/services/x11/xserver.nix b/nixpkgs/nixos/modules/services/x11/xserver.nix
index 0552095ba955..eb8c4c17e987 100644
--- a/nixpkgs/nixos/modules/services/x11/xserver.nix
+++ b/nixpkgs/nixos/modules/services/x11/xserver.nix
@@ -136,6 +136,7 @@ let
           fi
         done
 
+        echo '${cfg.filesSection}' >> $out
         echo 'EndSection' >> $out
 
         echo "$config" >> $out
@@ -151,6 +152,9 @@ in
       ./desktop-managers/default.nix
       (mkRemovedOptionModule [ "services" "xserver" "startGnuPGAgent" ]
         "See the 16.09 release notes for more information.")
+      (mkRemovedOptionModule
+        [ "services" "xserver" "startDbusSession" ]
+        "The user D-Bus session is now always socket activated and this option can safely be removed.")
       (mkRemovedOptionModule ["services" "xserver" "useXFS" ]
         "Use services.xserver.fontPath instead of useXFS")
     ];
@@ -298,14 +302,6 @@ in
         description = "DPI resolution to use for X server.";
       };
 
-      startDbusSession = mkOption {
-        type = types.bool;
-        default = true;
-        description = ''
-          Whether to start a new DBus session when you log in with dbus-launch.
-        '';
-      };
-
       updateDbusEnvironment = mkOption {
         type = types.bool;
         default = false;
@@ -366,6 +362,13 @@ in
         '';
       };
 
+      filesSection = mkOption {
+        type = types.lines;
+        default = "";
+        example = ''FontPath "/path/to/my/fonts"'';
+        description = "Contents of the first <literal>Files</literal> section of the X server configuration file.";
+      };
+
       deviceSection = mkOption {
         type = types.lines;
         default = "";
@@ -515,6 +518,19 @@ in
         '';
       };
 
+      logFile = mkOption {
+        type = types.nullOr types.str;
+        default = "/dev/null";
+        example = "/var/log/Xorg.0.log";
+        description = ''
+          Controls the file Xorg logs to.
+
+          The default of <literal>/dev/null</literal> is set so that systemd services (like <literal>displayManagers</literal>) only log to the journal and don't create their own log files.
+
+          Setting this to <literal>null</literal> will not pass the <literal>-logfile</literal> argument to Xorg which allows it to log to its default logfile locations instead (see <literal>man Xorg</literal>). You probably only want this behaviour when running Xorg manually (e.g. via <literal>startx</literal>).
+        '';
+      };
+
       verbose = mkOption {
         type = types.nullOr types.int;
         default = 3;
@@ -675,25 +691,24 @@ in
 
         script = "${cfg.displayManager.job.execCmd}";
 
+        # Stop restarting if the display manager stops (crashes) 2 times
+        # in one minute. Starting X typically takes 3-4s.
+        startLimitIntervalSec = 30;
+        startLimitBurst = 3;
         serviceConfig = {
           Restart = "always";
           RestartSec = "200ms";
           SyslogIdentifier = "display-manager";
-          # Stop restarting if the display manager stops (crashes) 2 times
-          # in one minute. Starting X typically takes 3-4s.
-          StartLimitInterval = "30s";
-          StartLimitBurst = "3";
         };
       };
 
     services.xserver.displayManager.xserverArgs =
       [ "-config ${configFile}"
         "-xkbdir" "${cfg.xkbDir}"
-        # Log at the default verbosity level to stderr rather than /var/log/X.*.log.
-         "-logfile" "/dev/null"
       ] ++ optional (cfg.display != null) ":${toString cfg.display}"
         ++ optional (cfg.tty     != null) "vt${toString cfg.tty}"
         ++ optional (cfg.dpi     != null) "-dpi ${toString cfg.dpi}"
+        ++ optional (cfg.logFile != null) "-logfile ${toString cfg.logFile}"
         ++ optional (cfg.verbose != null) "-verbose ${toString cfg.verbose}"
         ++ optional (!cfg.enableTCP) "-nolisten tcp"
         ++ optional (cfg.autoRepeatDelay != null) "-ardelay ${toString cfg.autoRepeatDelay}"
@@ -708,7 +723,7 @@ in
 
     system.extraDependencies = singleton (pkgs.runCommand "xkb-validated" {
       inherit (cfg) xkbModel layout xkbVariant xkbOptions;
-      nativeBuildInputs = [ pkgs.xkbvalidate ];
+      nativeBuildInputs = with pkgs.buildPackages; [ xkbvalidate ];
       preferLocalBuild = true;
     } ''
       xkbvalidate "$xkbModel" "$layout" "$xkbVariant" "$xkbOptions"
diff --git a/nixpkgs/nixos/modules/system/activation/activation-script.nix b/nixpkgs/nixos/modules/system/activation/activation-script.nix
index ddfd1af4a319..3a6930314b1a 100644
--- a/nixpkgs/nixos/modules/system/activation/activation-script.nix
+++ b/nixpkgs/nixos/modules/system/activation/activation-script.nix
@@ -25,9 +25,23 @@ let
       stdenv.cc.libc # nscd in update-users-groups.pl
       shadow
       nettools # needed for hostname
-      utillinux # needed for mount and mountpoint
+      util-linux # needed for mount and mountpoint
     ];
 
+  scriptType = with types;
+    let scriptOptions =
+      { deps = mkOption
+          { type = types.listOf types.str;
+            default = [ ];
+            description = "List of dependencies. The script will run after these.";
+          };
+        text = mkOption
+          { type = types.lines;
+            description = "The content of the script.";
+          };
+      };
+    in either str (submodule { options = scriptOptions; });
+
 in
 
 {
@@ -40,16 +54,14 @@ in
       default = {};
 
       example = literalExample ''
-        { stdio = {
-            text = '''
-              # Needed by some programs.
-              ln -sfn /proc/self/fd /dev/fd
-              ln -sfn /proc/self/fd/0 /dev/stdin
-              ln -sfn /proc/self/fd/1 /dev/stdout
-              ln -sfn /proc/self/fd/2 /dev/stderr
-            ''';
-            deps = [];
-          };
+        { stdio.text =
+          '''
+            # Needed by some programs.
+            ln -sfn /proc/self/fd /dev/fd
+            ln -sfn /proc/self/fd/0 /dev/stdin
+            ln -sfn /proc/self/fd/1 /dev/stdout
+            ln -sfn /proc/self/fd/2 /dev/stderr
+          ''';
         }
       '';
 
@@ -62,7 +74,7 @@ in
         idempotent and fast.
       '';
 
-      type = types.attrsOf types.unspecified; # FIXME
+      type = types.attrsOf scriptType;
 
       apply = set: {
         script =
@@ -125,7 +137,7 @@ in
         idempotent and fast.
       '';
 
-      type = types.attrsOf types.unspecified;
+      type = with types; attrsOf scriptType;
 
       apply = set: {
         script = ''
diff --git a/nixpkgs/nixos/modules/system/activation/top-level.nix b/nixpkgs/nixos/modules/system/activation/top-level.nix
index 2724d9f9cb6f..03d7e7493230 100644
--- a/nixpkgs/nixos/modules/system/activation/top-level.nix
+++ b/nixpkgs/nixos/modules/system/activation/top-level.nix
@@ -97,10 +97,11 @@ let
     allowSubstitutes = false;
     buildCommand = systemBuilder;
 
-    inherit (pkgs) utillinux coreutils;
+    inherit (pkgs) coreutils;
     systemd = config.systemd.package;
     shell = "${pkgs.bash}/bin/sh";
     su = "${pkgs.shadow.su}/bin/su";
+    utillinux = pkgs.util-linux;
 
     kernelParams = config.boot.kernelParams;
     installBootLoader =
diff --git a/nixpkgs/nixos/modules/system/boot/grow-partition.nix b/nixpkgs/nixos/modules/system/boot/grow-partition.nix
index 71a86c74772e..87c981b24cec 100644
--- a/nixpkgs/nixos/modules/system/boot/grow-partition.nix
+++ b/nixpkgs/nixos/modules/system/boot/grow-partition.nix
@@ -20,10 +20,10 @@ with lib;
     boot.initrd.extraUtilsCommands = ''
       copy_bin_and_libs ${pkgs.gawk}/bin/gawk
       copy_bin_and_libs ${pkgs.gnused}/bin/sed
-      copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk
-      copy_bin_and_libs ${pkgs.utillinux}/sbin/lsblk
+      copy_bin_and_libs ${pkgs.util-linux}/sbin/sfdisk
+      copy_bin_and_libs ${pkgs.util-linux}/sbin/lsblk
 
-      substitute "${pkgs.cloud-utils}/bin/.growpart-wrapped" "$out/bin/growpart" \
+      substitute "${pkgs.cloud-utils.guest}/bin/.growpart-wrapped" "$out/bin/growpart" \
         --replace "${pkgs.bash}/bin/sh" "/bin/sh" \
         --replace "awk" "gawk" \
         --replace "sed" "gnused"
diff --git a/nixpkgs/nixos/modules/system/boot/initrd-network.nix b/nixpkgs/nixos/modules/system/boot/initrd-network.nix
index ec794d6eb014..2a7417ed3715 100644
--- a/nixpkgs/nixos/modules/system/boot/initrd-network.nix
+++ b/nixpkgs/nixos/modules/system/boot/initrd-network.nix
@@ -32,8 +32,8 @@ let
         fi
         if [ -n "$dns" ]; then
           rm -f /etc/resolv.conf
-          for i in $dns; do
-            echo "nameserver $dns" >> /etc/resolv.conf
+          for server in $dns; do
+            echo "nameserver $server" >> /etc/resolv.conf
           done
         fi
       fi
diff --git a/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix b/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix
index f7ef26103709..00ac83a18972 100644
--- a/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix
+++ b/nixpkgs/nixos/modules/system/boot/initrd-ssh.nix
@@ -159,9 +159,14 @@ in
 
     boot.initrd.extraUtilsCommandsTest = ''
       # sshd requires a host key to check config, so we pass in the test's
+      tmpkey="$(mktemp initrd-ssh-testkey.XXXXXXXXXX)"
+      cp "${../../../tests/initrd-network-ssh/ssh_host_ed25519_key}" "$tmpkey"
+      # keys from Nix store are world-readable, which sshd doesn't like
+      chmod 600 "$tmpkey"
       echo -n ${escapeShellArg sshdConfig} |
         $out/bin/sshd -t -f /dev/stdin \
-        -h ${../../../tests/initrd-network-ssh/ssh_host_ed25519_key}
+        -h "$tmpkey"
+      rm "$tmpkey"
     '';
 
     boot.initrd.network.postCommands = ''
diff --git a/nixpkgs/nixos/modules/system/boot/kernel.nix b/nixpkgs/nixos/modules/system/boot/kernel.nix
index 43871f439f7f..ed7226331d70 100644
--- a/nixpkgs/nixos/modules/system/boot/kernel.nix
+++ b/nixpkgs/nixos/modules/system/boot/kernel.nix
@@ -227,7 +227,7 @@ in
             "xhci_pci"
             "usbhid"
             "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat"
-            "hid_logitech_hidpp" "hid_logitech_dj"
+            "hid_logitech_hidpp" "hid_logitech_dj" "hid_microsoft"
 
           ] ++ optionals (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [
             # Misc. x86 keyboard stuff.
diff --git a/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix b/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix
index 20e39628eabb..df5dfaa554bc 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix
@@ -66,7 +66,7 @@ let
         extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels
         default fsIdentifier efiSupport efiInstallAsRemovable gfxmodeEfi gfxmodeBios gfxpayloadEfi gfxpayloadBios;
       path = with pkgs; makeBinPath (
-        [ coreutils gnused gnugrep findutils diffutils btrfs-progs utillinux mdadm ]
+        [ coreutils gnused gnugrep findutils diffutils btrfs-progs util-linux mdadm ]
         ++ optional (cfg.efiSupport && (cfg.version == 2)) efibootmgr
         ++ optionals cfg.useOSProber [ busybox os-prober ]);
       font = if cfg.font == null then ""
@@ -705,7 +705,7 @@ in
         let
           install-grub-pl = pkgs.substituteAll {
             src = ./install-grub.pl;
-            inherit (pkgs) utillinux;
+            utillinux = pkgs.util-linux;
             btrfsprogs = pkgs.btrfs-progs;
           };
         in pkgs.writeScript "install-grub.sh" (''
@@ -741,7 +741,7 @@ in
             + "'boot.loader.grub.mirroredBoots' to make the system bootable.";
         }
         {
-          assertion = cfg.efiSupport || all (c: c < 2) (mapAttrsToList (_: c: c) bootDeviceCounters);
+          assertion = cfg.efiSupport || all (c: c < 2) (mapAttrsToList (n: c: if n == "nodev" then 0 else c) bootDeviceCounters);
           message = "You cannot have duplicated devices in mirroredBoots";
         }
         {
diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
index 65c7b825f855..97e824fe629c 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
+++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
@@ -200,9 +200,7 @@ def main():
     else:
         # Update bootloader to latest if needed
         systemd_version = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[1]
-        # Ideally this should use check_output as well, but as a temporary
-        # work-around for #97433 we ignore any errors.
-        sdboot_status = subprocess.run(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "status"], universal_newlines=True, stdout=subprocess.PIPE).stdout
+        sdboot_status = subprocess.check_output(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "status"], universal_newlines=True)
 
         # See status_binaries() in systemd bootctl.c for code which generates this
         m = re.search("^\W+File:.*/EFI/(BOOT|systemd)/.*\.efi \(systemd-boot (\d+)\)$",
diff --git a/nixpkgs/nixos/modules/system/boot/luksroot.nix b/nixpkgs/nixos/modules/system/boot/luksroot.nix
index 88190e8200b1..8dd2ea20519a 100644
--- a/nixpkgs/nixos/modules/system/boot/luksroot.nix
+++ b/nixpkgs/nixos/modules/system/boot/luksroot.nix
@@ -404,7 +404,7 @@ let
           echo "Please move your mouse to create needed randomness."
         ''}
           echo "Waiting for your FIDO2 device..."
-          fido2luks -i open ${device} ${name} ${fido2.credential} --await-dev ${toString fido2.gracePeriod} --salt string:$passphrase
+          fido2luks open ${device} ${name} ${fido2.credential} --await-dev ${toString fido2.gracePeriod} --salt string:$passphrase
         if [ $? -ne 0 ]; then
           echo "No FIDO2 key found, falling back to normal open procedure"
           open_normally
diff --git a/nixpkgs/nixos/modules/system/boot/networkd.nix b/nixpkgs/nixos/modules/system/boot/networkd.nix
index 47689b2a4700..3b01bc00bafa 100644
--- a/nixpkgs/nixos/modules/system/boot/networkd.nix
+++ b/nixpkgs/nixos/modules/system/boot/networkd.nix
@@ -648,11 +648,13 @@ let
           "RapidCommit"
           "ForceDHCPv6PDOtherInformation"
           "PrefixDelegationHint"
+          "RouteMetric"
         ])
         (assertValueOneOf "UseDNS" boolValues)
         (assertValueOneOf "UseNTP" boolValues)
         (assertValueOneOf "RapidCommit" boolValues)
         (assertValueOneOf "ForceDHCPv6PDOtherInformation" boolValues)
+        (assertInt "RouteMetric")
       ];
 
       sectionDHCPServer = checkUnitConfig "DHCPServer" [
diff --git a/nixpkgs/nixos/modules/system/boot/pbkdf2-sha512.c b/nixpkgs/nixos/modules/system/boot/pbkdf2-sha512.c
index b40c383ac023..67e989957ba6 100644
--- a/nixpkgs/nixos/modules/system/boot/pbkdf2-sha512.c
+++ b/nixpkgs/nixos/modules/system/boot/pbkdf2-sha512.c
@@ -35,4 +35,4 @@ int main(int argc, char** argv)
 	fwrite(key, 1, key_length, stdout);
 
 	return 0;
-}
\ No newline at end of file
+}
diff --git a/nixpkgs/nixos/modules/system/boot/plymouth.nix b/nixpkgs/nixos/modules/system/boot/plymouth.nix
index 55e5b07ed615..ddf5ef8a0a6a 100644
--- a/nixpkgs/nixos/modules/system/boot/plymouth.nix
+++ b/nixpkgs/nixos/modules/system/boot/plymouth.nix
@@ -9,7 +9,7 @@ let
 
   cfg = config.boot.plymouth;
 
-  nixosBreezePlymouth = pkgs.breeze-plymouth.override {
+  nixosBreezePlymouth = pkgs.plasma5.breeze-plymouth.override {
     logoFile = cfg.logo;
     logoName = "nixos";
     osName = "NixOS";
diff --git a/nixpkgs/nixos/modules/system/boot/resolved.nix b/nixpkgs/nixos/modules/system/boot/resolved.nix
index b024f9cf5ee9..7fe8f4dfb7e3 100644
--- a/nixpkgs/nixos/modules/system/boot/resolved.nix
+++ b/nixpkgs/nixos/modules/system/boot/resolved.nix
@@ -1,4 +1,4 @@
-{ config, lib, ... }:
+{ config, pkgs, lib, ... }:
 
 with lib;
 let
@@ -136,7 +136,7 @@ in
       }
     ];
 
-    users.users.resolved.group = "systemd-resolve";
+    users.users.systemd-resolve.group = "systemd-resolve";
 
     # add resolve to nss hosts database if enabled and nscd enabled
     # system.nssModules is configured in nixos/modules/system/boot/systemd.nix
@@ -150,6 +150,9 @@ in
       wantedBy = [ "multi-user.target" ];
       aliases = [ "dbus-org.freedesktop.resolve1.service" ];
       restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ];
+      # Upstream bug: https://github.com/systemd/systemd/issues/18078
+      # systemd-resolved without libidn2 is broken
+      environment.LD_LIBRARY_PATH = "${lib.getLib pkgs.libidn2}/lib";
     };
 
     environment.etc = {
diff --git a/nixpkgs/nixos/modules/system/boot/shutdown.nix b/nixpkgs/nixos/modules/system/boot/shutdown.nix
index 11041066e07c..8cda7b3aabe8 100644
--- a/nixpkgs/nixos/modules/system/boot/shutdown.nix
+++ b/nixpkgs/nixos/modules/system/boot/shutdown.nix
@@ -18,7 +18,7 @@ with lib;
 
       serviceConfig = {
         Type = "oneshot";
-        ExecStart = "${pkgs.utillinux}/sbin/hwclock --systohc ${if config.time.hardwareClockInLocalTime then "--localtime" else "--utc"}";
+        ExecStart = "${pkgs.util-linux}/sbin/hwclock --systohc ${if config.time.hardwareClockInLocalTime then "--localtime" else "--utc"}";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
index f7c2940049e5..abc1a0af48a6 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
@@ -120,7 +120,7 @@ eval "exec $logOutFd>&1 $logErrFd>&2"
 if test -w /dev/kmsg; then
     tee -i < /tmp/stage-1-init.log.fifo /proc/self/fd/"$logOutFd" | while read -r line; do
         if test -n "$line"; then
-            echo "<7>stage-1-init: $line" > /dev/kmsg
+            echo "<7>stage-1-init: [$(date)] $line" > /dev/kmsg
         fi
     done &
 else
@@ -219,6 +219,9 @@ done
 @preDeviceCommands@
 echo "running udev..."
 ln -sfn /proc/self/fd /dev/fd
+ln -sfn /proc/self/fd/0 /dev/stdin
+ln -sfn /proc/self/fd/1 /dev/stdout
+ln -sfn /proc/self/fd/2 /dev/stderr
 mkdir -p /etc/systemd
 ln -sfn @linkUnits@ /etc/systemd/network
 mkdir -p /etc/udev
@@ -356,6 +359,7 @@ mountFS() {
     case $options in
         *x-nixos.autoresize*)
             if [ "$fsType" = ext2 -o "$fsType" = ext3 -o "$fsType" = ext4 ]; then
+                modprobe "$fsType"
                 echo "resizing $device..."
                 e2fsck -fp "$device"
                 resize2fs "$device"
diff --git a/nixpkgs/nixos/modules/system/boot/stage-1.nix b/nixpkgs/nixos/modules/system/boot/stage-1.nix
index 6823e12847c2..86bfde6349c3 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-1.nix
+++ b/nixpkgs/nixos/modules/system/boot/stage-1.nix
@@ -107,8 +107,8 @@ let
         copy_bin_and_libs $BIN
       done
 
-      # Copy some utillinux stuff.
-      copy_bin_and_libs ${pkgs.utillinux}/sbin/blkid
+      # Copy some util-linux stuff.
+      copy_bin_and_libs ${pkgs.util-linux}/sbin/blkid
 
       # Copy dmsetup and lvm.
       copy_bin_and_libs ${getBin pkgs.lvm2}/bin/dmsetup
@@ -235,7 +235,7 @@ let
             --replace scsi_id ${extraUtils}/bin/scsi_id \
             --replace cdrom_id ${extraUtils}/bin/cdrom_id \
             --replace ${pkgs.coreutils}/bin/basename ${extraUtils}/bin/basename \
-            --replace ${pkgs.utillinux}/bin/blkid ${extraUtils}/bin/blkid \
+            --replace ${pkgs.util-linux}/bin/blkid ${extraUtils}/bin/blkid \
             --replace ${getBin pkgs.lvm2}/bin ${extraUtils}/bin \
             --replace ${pkgs.mdadm}/sbin ${extraUtils}/sbin \
             --replace ${pkgs.bash}/bin/sh ${extraUtils}/bin/sh \
@@ -308,7 +308,7 @@ let
   # the initial RAM disk.
   initialRamdisk = pkgs.makeInitrd {
     name = "initrd-${kernel-name}";
-    inherit (config.boot.initrd) compressor prepend;
+    inherit (config.boot.initrd) compressor compressorArgs prepend;
 
     contents =
       [ { object = bootStage1;
@@ -334,7 +334,9 @@ let
 
   # Script to add secret files to the initrd at bootloader update time
   initialRamdiskSecretAppender =
-    pkgs.writeScriptBin "append-initrd-secrets"
+    let
+      compressorExe = initialRamdisk.compressorExecutableFunction pkgs;
+    in pkgs.writeScriptBin "append-initrd-secrets"
       ''
         #!${pkgs.bash}/bin/bash -e
         function usage {
@@ -376,7 +378,7 @@ let
          }
 
         (cd "$tmp" && find . -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null) | \
-          ${config.boot.initrd.compressor} >> "$1"
+          ${compressorExe} ${lib.escapeShellArgs initialRamdisk.compressorArgs} >> "$1"
       '';
 
 in
@@ -511,13 +513,28 @@ in
     };
 
     boot.initrd.compressor = mkOption {
-      internal = true;
-      default = "gzip -9n";
-      type = types.str;
-      description = "The compressor to use on the initrd image.";
+      default = "gzip";
+      type = types.unspecified; # We don't have a function type...
+      description = ''
+        The compressor to use on the initrd image. May be any of:
+
+        <itemizedlist>
+         <listitem><para>The name of one of the predefined compressors, see <filename>pkgs/build-support/kernel/initrd-compressor-meta.nix</filename> for the definitions.</para></listitem>
+         <listitem><para>A function which, given the nixpkgs package set, returns the path to a compressor tool, e.g. <literal>pkgs: "''${pkgs.pigz}/bin/pigz"</literal></para></listitem>
+         <listitem><para>(not recommended, because it does not work when cross-compiling) the full path to a compressor tool, e.g. <literal>"''${pkgs.pigz}/bin/pigz"</literal></para></listitem>
+        </itemizedlist>
+
+        The given program should read data from stdin and write it to stdout compressed.
+      '';
       example = "xz";
     };
 
+    boot.initrd.compressorArgs = mkOption {
+      default = null;
+      type = types.nullOr (types.listOf types.str);
+      description = "Arguments to pass to the compressor for the initrd image, or null to use the compressor's defaults.";
+    };
+
     boot.initrd.secrets = mkOption
       { default = {};
         type = types.attrsOf (types.nullOr types.path);
diff --git a/nixpkgs/nixos/modules/system/boot/stage-2.nix b/nixpkgs/nixos/modules/system/boot/stage-2.nix
index dd6d83ee0094..94bc34fea0db 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-2.nix
+++ b/nixpkgs/nixos/modules/system/boot/stage-2.nix
@@ -17,7 +17,7 @@ let
     inherit (config.system.build) earlyMountScript;
     path = lib.makeBinPath ([
       pkgs.coreutils
-      pkgs.utillinux
+      pkgs.util-linux
     ] ++ lib.optional useHostResolvConf pkgs.openresolv);
     fsPackagesPath = lib.makeBinPath config.system.fsPackages;
     postBootCommands = pkgs.writeText "local-cmds"
diff --git a/nixpkgs/nixos/modules/system/boot/systemd-unit-options.nix b/nixpkgs/nixos/modules/system/boot/systemd-unit-options.nix
index 5addc6f9ca44..4154389b2ce5 100644
--- a/nixpkgs/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixpkgs/nixos/modules/system/boot/systemd-unit-options.nix
@@ -210,12 +210,21 @@ in rec {
       '';
     };
 
+    startLimitBurst = mkOption {
+       type = types.int;
+       description = ''
+         Configure unit start rate limiting. Units which are started
+         more than startLimitBurst times within an interval time
+         interval are not permitted to start any more.
+       '';
+    };
+
     startLimitIntervalSec = mkOption {
        type = types.int;
        description = ''
          Configure unit start rate limiting. Units which are started
-         more than burst times within an interval time interval are
-         not permitted to start any more.
+         more than startLimitBurst times within an interval time
+         interval are not permitted to start any more.
        '';
     };
 
@@ -245,8 +254,7 @@ in rec {
     serviceConfig = mkOption {
       default = {};
       example =
-        { StartLimitInterval = 10;
-          RestartSec = 5;
+        { RestartSec = 5;
         };
       type = types.addCheck (types.attrsOf unitOption) checkService;
       description = ''
diff --git a/nixpkgs/nixos/modules/system/boot/systemd.nix b/nixpkgs/nixos/modules/system/boot/systemd.nix
index 12a4e996fcae..080a018047fe 100644
--- a/nixpkgs/nixos/modules/system/boot/systemd.nix
+++ b/nixpkgs/nixos/modules/system/boot/systemd.nix
@@ -243,6 +243,8 @@ let
           OnFailure = toString config.onFailure; }
         // optionalAttrs (options.startLimitIntervalSec.isDefined) {
           StartLimitIntervalSec = toString config.startLimitIntervalSec;
+        } // optionalAttrs (options.startLimitBurst.isDefined) {
+          StartLimitBurst = toString config.startLimitBurst;
         };
     };
   };
@@ -548,6 +550,14 @@ in
       '';
     };
 
+    systemd.enableUnifiedCgroupHierarchy = mkOption {
+      default = true;
+      type = types.bool;
+      description = ''
+        Whether to enable the unified cgroup hierarchy (cgroupsv2).
+      '';
+    };
+
     systemd.coredump.enable = mkOption {
       default = true;
       type = types.bool;
@@ -884,14 +894,25 @@ in
 
   config = {
 
-    warnings = concatLists (mapAttrsToList (name: service:
-      let
-        type = service.serviceConfig.Type or "";
-        restart = service.serviceConfig.Restart or "no";
-      in optional
-      (type == "oneshot" && (restart == "always" || restart == "on-success"))
-      "Service '${name}.service' with 'Type=oneshot' cannot have 'Restart=always' or 'Restart=on-success'")
-      cfg.services);
+    warnings = concatLists (
+      mapAttrsToList
+        (name: service:
+          let
+            type = service.serviceConfig.Type or "";
+            restart = service.serviceConfig.Restart or "no";
+            hasDeprecated = builtins.hasAttr "StartLimitInterval" service.serviceConfig;
+          in
+            concatLists [
+              (optional (type == "oneshot" && (restart == "always" || restart == "on-success"))
+                "Service '${name}.service' with 'Type=oneshot' cannot have 'Restart=always' or 'Restart=on-success'"
+              )
+              (optional hasDeprecated
+                "Service '${name}.service' uses the attribute 'StartLimitInterval' in the Service section, which is deprecated. See https://github.com/NixOS/nixpkgs/issues/45786."
+              )
+            ]
+        )
+        cfg.services
+    );
 
     system.build.units = cfg.units;
 
@@ -1167,6 +1188,7 @@ in
     boot.kernel.sysctl = mkIf (!cfg.coredump.enable) {
       "kernel.core_pattern" = "core";
     };
+    boot.kernelParams = optional (!cfg.enableUnifiedCgroupHierarchy) "systemd.unified_cgroup_hierarchy=0";
   };
 
   # FIXME: Remove these eventually.
diff --git a/nixpkgs/nixos/modules/tasks/auto-upgrade.nix b/nixpkgs/nixos/modules/tasks/auto-upgrade.nix
index 69385e5f2fe0..b19b688a1fb8 100644
--- a/nixpkgs/nixos/modules/tasks/auto-upgrade.nix
+++ b/nixpkgs/nixos/modules/tasks/auto-upgrade.nix
@@ -109,9 +109,8 @@ in {
       '';
     }];
 
-    system.autoUpgrade.flags = [ "--no-build-output" ]
-      ++ (if cfg.flake == null then
-        (if cfg.channel == null then
+    system.autoUpgrade.flags = (if cfg.flake == null then
+        [ "--no-build-output" ] ++ (if cfg.channel == null then
           [ "--upgrade" ]
         else [
           "-I"
diff --git a/nixpkgs/nixos/modules/tasks/filesystems.nix b/nixpkgs/nixos/modules/tasks/filesystems.nix
index 3ea67dac7146..a055072f9c96 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems.nix
@@ -286,7 +286,7 @@ in
             before = [ mountPoint' "systemd-fsck@${device'}.service" ];
             requires = [ device'' ];
             after = [ device'' ];
-            path = [ pkgs.utillinux ] ++ config.system.fsPackages;
+            path = [ pkgs.util-linux ] ++ config.system.fsPackages;
             script =
               ''
                 if ! [ -e "${fs.device}" ]; then exit 1; fi
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix b/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix
index 5fda24adb978..ac41ba5f93a4 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix
@@ -49,8 +49,8 @@ in
     }
 
     (mkIf ((elem "bcachefs" config.boot.initrd.supportedFilesystems) || (bootFs != {})) {
-      # the cryptographic modules are required only for decryption attempts
-      boot.initrd.availableKernelModules = [ "bcachefs" "chacha20" "poly1305" ];
+      # chacha20 and poly1305 are required only for decryption attempts
+      boot.initrd.availableKernelModules = [ "bcachefs" "sha256" "chacha20" "poly1305" ];
 
       boot.initrd.extraUtilsCommands = ''
         copy_bin_and_libs ${pkgs.bcachefs-tools}/bin/bcachefs
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/nfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/nfs.nix
index ddcc0ed8f5a4..fd35c35d32ad 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/nfs.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/nfs.nix
@@ -10,20 +10,9 @@ let
 
   rpcMountpoint = "${nfsStateDir}/rpc_pipefs";
 
-  idmapdConfFile = pkgs.writeText "idmapd.conf" ''
-    [General]
-    Pipefs-Directory = ${rpcMountpoint}
-    ${optionalString (config.networking.domain != null)
-      "Domain = ${config.networking.domain}"}
-
-    [Mapping]
-    Nobody-User = nobody
-    Nobody-Group = nogroup
-
-    [Translation]
-    Method = nsswitch
-  '';
+  format = pkgs.formats.ini {};
 
+  idmapdConfFile = format.generate "idmapd.conf" cfg.idmapd.settings;
   nfsConfFile = pkgs.writeText "nfs.conf" cfg.extraConfig;
   requestKeyConfFile = pkgs.writeText "request-key.conf" ''
     create id_resolver * * ${pkgs.nfs-utils}/bin/nfsidmap -t 600 %k %d
@@ -38,6 +27,25 @@ in
 
   options = {
     services.nfs = {
+      idmapd.settings = mkOption {
+        type = format.type;
+        default = {};
+        description = ''
+          libnfsidmap configuration. Refer to
+          <link xlink:href="https://linux.die.net/man/5/idmapd.conf"/>
+          for details.
+        '';
+        example = literalExample ''
+          {
+            Translation = {
+              GSS-Methods = "static,nsswitch";
+            };
+            Static = {
+              "root/hostname.domain.com@REALM.COM" = "root";
+            };
+          }
+        '';
+      };
       extraConfig = mkOption {
         type = types.lines;
         default = "";
@@ -54,6 +62,20 @@ in
 
     services.rpcbind.enable = true;
 
+    services.nfs.idmapd.settings = {
+      General = mkMerge [
+        { Pipefs-Directory = rpcMountpoint; }
+        (mkIf (config.networking.domain != null) { Domain = config.networking.domain; })
+      ];
+      Mapping = {
+        Nobody-User = "nobody";
+        Nobody-Group = "nogroup";
+      };
+      Translation = {
+        Method = "nsswitch";
+      };
+    };
+
     system.fsPackages = [ pkgs.nfs-utils ];
 
     boot.initrd.kernelModules = mkIf inInitrd [ "nfs" ];
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/unionfs-fuse.nix b/nixpkgs/nixos/modules/tasks/filesystems/unionfs-fuse.nix
index 1dcc4c87e3ce..f54f3559c341 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/unionfs-fuse.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/unionfs-fuse.nix
@@ -18,9 +18,9 @@
 
       boot.initrd.postDeviceCommands = ''
           # Hacky!!! fuse hard-codes the path to mount
-          mkdir -p /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}-bin/bin
-          ln -s $(which mount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}-bin/bin
-          ln -s $(which umount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}-bin/bin
+          mkdir -p /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.util-linux.name}-bin/bin
+          ln -s $(which mount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.util-linux.name}-bin/bin
+          ln -s $(which umount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.util-linux.name}-bin/bin
         '';
     })
 
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix
index 9ca7c6fb3431..6becc6962735 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix
@@ -175,14 +175,10 @@ in
 
       forceImportAll = mkOption {
         type = types.bool;
-        default = true;
+        default = false;
         description = ''
           Forcibly import all ZFS pool(s).
 
-          This is enabled by default for backwards compatibility purposes, but it is highly
-          recommended to disable this option, as it bypasses some of the safeguards ZFS uses
-          to protect your ZFS pools.
-
           If you set this option to <literal>false</literal> and NixOS subsequently fails to
           import your non-root ZFS pool(s), you should manually import each pool with
           "zpool import -f &lt;pool-name&gt;", and then reboot. You should only need to do
@@ -444,7 +440,7 @@ in
           pkgs.gnugrep
           pkgs.gnused
           pkgs.nettools
-          pkgs.utillinux
+          pkgs.util-linux
         ];
       };
 
@@ -507,6 +503,7 @@ in
               Type = "oneshot";
               RemainAfterExit = true;
             };
+            environment.ZFS_FORCE = optionalString cfgZfs.forceImportAll "-f";
             script = (importLib {
               # See comments at importLib definition.
               zpoolCmd="${packages.zfsUser}/sbin/zpool";
diff --git a/nixpkgs/nixos/modules/tasks/lvm.nix b/nixpkgs/nixos/modules/tasks/lvm.nix
index 2c3cc4c5467d..98a0e2ddef90 100644
--- a/nixpkgs/nixos/modules/tasks/lvm.nix
+++ b/nixpkgs/nixos/modules/tasks/lvm.nix
@@ -21,6 +21,10 @@ in {
   };
 
   config = mkMerge [
+    ({
+      # minimal configuration file to make lvmconfig/lvm2-activation-generator happy
+      environment.etc."lvm/lvm.conf".text = "config {}";
+    })
     (mkIf (!config.boot.isContainer) {
       systemd.tmpfiles.packages = [ cfg.package.out ];
       environment.systemPackages = [ cfg.package ];
diff --git a/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix b/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix
index 23e1e611a71e..088bffd7c508 100644
--- a/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix
+++ b/nixpkgs/nixos/modules/tasks/network-interfaces-systemd.nix
@@ -93,7 +93,17 @@ in
             (if i.useDHCP != null then i.useDHCP else false));
           address = forEach (interfaceIps i)
             (ip: "${ip.address}/${toString ip.prefixLength}");
-          networkConfig.IPv6PrivacyExtensions = "kernel";
+          # IPv6PrivacyExtensions=kernel seems to be broken with networkd.
+          # Instead of using IPv6PrivacyExtensions=kernel, configure it according to the value of
+          # `tempAddress`:
+          networkConfig.IPv6PrivacyExtensions = {
+            # generate temporary addresses and use them by default
+            "default" = true;
+            # generate temporary addresses but keep using the standard EUI-64 ones by default
+            "enabled" = "prefer-public";
+            # completely disable temporary addresses
+            "disabled" = false;
+          }.${i.tempAddress};
           linkConfig = optionalAttrs (i.macAddress != null) {
             MACAddress = i.macAddress;
           } // optionalAttrs (i.mtu != null) {
diff --git a/nixpkgs/nixos/modules/tasks/network-interfaces.nix b/nixpkgs/nixos/modules/tasks/network-interfaces.nix
index c0e4d3979fda..afb9c5404169 100644
--- a/nixpkgs/nixos/modules/tasks/network-interfaces.nix
+++ b/nixpkgs/nixos/modules/tasks/network-interfaces.nix
@@ -381,15 +381,20 @@ in
       # syntax). Note: We also allow underscores for compatibility/legacy
       # reasons (as undocumented feature):
       type = types.strMatching
-        "^$|^[[:alpha:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$";
+        "^$|^[[:alnum:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$";
       description = ''
         The name of the machine. Leave it empty if you want to obtain it from a
         DHCP server (if using DHCP). The hostname must be a valid DNS label (see
-        RFC 1035 section 2.3.1: "Preferred name syntax") and as such must not
-        contain the domain part. This means that the hostname must start with a
-        letter, end with a letter or digit, and have as interior characters only
+        RFC 1035 section 2.3.1: "Preferred name syntax", RFC 1123 section 2.1:
+        "Host Names and Numbers") and as such must not contain the domain part.
+        This means that the hostname must start with a letter or digit,
+        end with a letter or digit, and have as interior characters only
         letters, digits, and hyphen. The maximum length is 63 characters.
         Additionally it is recommended to only use lower-case characters.
+        If (e.g. for legacy reasons) a FQDN is required as the Linux kernel
+        network node hostname (uname --nodename) the option
+        boot.kernel.sysctl."kernel.hostname" can be used as a workaround (but
+        the 64 character limit still applies).
       '';
     };
 
@@ -469,7 +474,7 @@ in
 
     networking.search = mkOption {
       default = [];
-      example = [ "example.com" "local.domain" ];
+      example = [ "example.com" "home.arpa" ];
       type = types.listOf types.str;
       description = ''
         The list of search paths used when resolving domain names.
@@ -478,7 +483,7 @@ in
 
     networking.domain = mkOption {
       default = null;
-      example = "home";
+      example = "home.arpa";
       type = types.nullOr types.str;
       description = ''
         The domain.  It can be left empty if it is auto-detected through DHCP.
@@ -1057,7 +1062,6 @@ in
       ];
 
     boot.kernelModules = [ ]
-      ++ optional cfg.enableIPv6 "ipv6"
       ++ optional hasVirtuals "tun"
       ++ optional hasSits "sit"
       ++ optional hasBonds "bonding";
@@ -1242,7 +1246,7 @@ in
             '';
 
             # Udev attributes for systemd to name the device and to create a .device target.
-            systemdAttrs = n: ''NAME:="${n}", ENV{INTERFACE}:="${n}", ENV{SYSTEMD_ALIAS}:="/sys/subsystem/net/devices/${n}", TAG+="systemd"'';
+            systemdAttrs = n: ''NAME:="${n}", ENV{INTERFACE}="${n}", ENV{SYSTEMD_ALIAS}="/sys/subsystem/net/devices/${n}", TAG+="systemd"'';
           in
           flip (concatMapStringsSep "\n") (attrNames wlanDeviceInterfaces) (device:
             let
diff --git a/nixpkgs/nixos/modules/testing/test-instrumentation.nix b/nixpkgs/nixos/modules/testing/test-instrumentation.nix
index c0ec76e8a3a3..be5fa88b8ade 100644
--- a/nixpkgs/nixos/modules/testing/test-instrumentation.nix
+++ b/nixpkgs/nixos/modules/testing/test-instrumentation.nix
@@ -45,13 +45,22 @@ with import ../../lib/qemu-flags.nix { inherit pkgs; };
     systemd.services."serial-getty@${qemuSerialDevice}".enable = false;
     systemd.services."serial-getty@hvc0".enable = false;
 
-    # Only use a serial console, no TTY.
-    # NOTE: optionalAttrs
-    #       test-instrumentation.nix appears to be used without qemu-vm.nix, so
-    #       we avoid defining consoles if not possible.
-    # TODO: refactor such that test-instrumentation can import qemu-vm
-    #       or declare virtualisation.qemu.console option in a module that's always imported
-    virtualisation = lib.optionalAttrs (options ? virtualisation.qemu.consoles) { qemu.consoles = [ qemuSerialDevice ]; };
+    # Only set these settings when the options exist. Some tests (e.g. those
+    # that do not specify any nodes, or an empty attr set as nodes) will not
+    # have the QEMU module loaded and thuse these options can't and should not
+    # be set.
+    virtualisation = lib.optionalAttrs (options ? virtualisation.qemu) {
+      qemu = {
+        # Only use a serial console, no TTY.
+        # NOTE: optionalAttrs
+        #       test-instrumentation.nix appears to be used without qemu-vm.nix, so
+        #       we avoid defining consoles if not possible.
+        # TODO: refactor such that test-instrumentation can import qemu-vm
+        #       or declare virtualisation.qemu.console option in a module that's always imported
+        consoles = [ qemuSerialDevice ];
+        package  = lib.mkDefault pkgs.qemu_test;
+      };
+    };
 
     boot.initrd.preDeviceCommands =
       ''
@@ -116,6 +125,10 @@ with import ../../lib/qemu-flags.nix { inherit pkgs; };
     users.users.root.initialHashedPassword = mkOverride 150 "";
 
     services.xserver.displayManager.job.logToJournal = true;
+
+    # Make sure we use the Guest Agent from the QEMU package for testing
+    # to reduce the closure size required for the tests.
+    services.qemuGuest.package = pkgs.qemu_test.ga;
   };
 
 }
diff --git a/nixpkgs/nixos/modules/virtualisation/amazon-image.nix b/nixpkgs/nixos/modules/virtualisation/amazon-image.nix
index 20d48add7129..26297a7d0f1f 100644
--- a/nixpkgs/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixpkgs/nixos/modules/virtualisation/amazon-image.nix
@@ -11,6 +11,7 @@ with lib;
 let
   cfg = config.ec2;
   metadataFetcher = import ./ec2-metadata-fetcher.nix {
+    inherit (pkgs) curl;
     targetRoot = "$targetRoot/";
     wgetExtraOptions = "-q";
   };
@@ -48,7 +49,7 @@ in
     ];
     boot.initrd.kernelModules = [ "xen-blkfront" "xen-netfront" ];
     boot.initrd.availableKernelModules = [ "ixgbevf" "ena" "nvme" ];
-    boot.kernelParams = mkIf cfg.hvm [ "console=ttyS0" ];
+    boot.kernelParams = mkIf cfg.hvm [ "console=ttyS0" "random.trust_cpu=on" ];
 
     # Prevent the nouveau kernel module from being loaded, as it
     # interferes with the nvidia/nvidia-uvm modules needed for CUDA.
@@ -123,7 +124,7 @@ in
     boot.initrd.extraUtilsCommands =
       ''
         # We need swapon in the initrd.
-        copy_bin_and_libs ${pkgs.utillinux}/sbin/swapon
+        copy_bin_and_libs ${pkgs.util-linux}/sbin/swapon
       '';
 
     # Don't put old configurations in the GRUB menu.  The user has no
diff --git a/nixpkgs/nixos/modules/virtualisation/amazon-init.nix b/nixpkgs/nixos/modules/virtualisation/amazon-init.nix
index 8c12e0e49bf5..c5470b7af09b 100644
--- a/nixpkgs/nixos/modules/virtualisation/amazon-init.nix
+++ b/nixpkgs/nixos/modules/virtualisation/amazon-init.nix
@@ -7,7 +7,7 @@ let
     echo "attempting to fetch configuration from EC2 user data..."
 
     export HOME=/root
-    export PATH=${pkgs.lib.makeBinPath [ config.nix.package pkgs.systemd pkgs.gnugrep pkgs.git pkgs.gnutar pkgs.gzip pkgs.gnused config.system.build.nixos-rebuild]}:$PATH
+    export PATH=${pkgs.lib.makeBinPath [ config.nix.package pkgs.systemd pkgs.gnugrep pkgs.git pkgs.gnutar pkgs.gzip pkgs.gnused pkgs.xz config.system.build.nixos-rebuild]}:$PATH
     export NIX_PATH=nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels
 
     userData=/etc/ec2-metadata/user-data
diff --git a/nixpkgs/nixos/modules/virtualisation/azure-agent.nix b/nixpkgs/nixos/modules/virtualisation/azure-agent.nix
index e85482af8392..81413792eda0 100644
--- a/nixpkgs/nixos/modules/virtualisation/azure-agent.nix
+++ b/nixpkgs/nixos/modules/virtualisation/azure-agent.nix
@@ -22,7 +22,7 @@ let
                     nettools # for hostname
                     procps # for pidof
                     shadow # for useradd, usermod
-                    utillinux # for (u)mount, fdisk, sfdisk, mkswap
+                    util-linux # for (u)mount, fdisk, sfdisk, mkswap
                     parted
                   ];
     pythonPath = [ pythonPackages.pyasn1 ];
diff --git a/nixpkgs/nixos/modules/virtualisation/brightbox-image.nix b/nixpkgs/nixos/modules/virtualisation/brightbox-image.nix
index d0efbcc808aa..4498e3a73618 100644
--- a/nixpkgs/nixos/modules/virtualisation/brightbox-image.nix
+++ b/nixpkgs/nixos/modules/virtualisation/brightbox-image.nix
@@ -27,7 +27,7 @@ in
               popd
             '';
           diskImageBase = "nixos-image-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}.raw";
-          buildInputs = [ pkgs.utillinux pkgs.perl ];
+          buildInputs = [ pkgs.util-linux pkgs.perl ];
           exportReferencesGraph =
             [ "closure" config.system.build.toplevel ];
         }
diff --git a/nixpkgs/nixos/modules/virtualisation/docker.nix b/nixpkgs/nixos/modules/virtualisation/docker.nix
index d87ada35a0ae..ec257801b330 100644
--- a/nixpkgs/nixos/modules/virtualisation/docker.nix
+++ b/nixpkgs/nixos/modules/virtualisation/docker.nix
@@ -155,6 +155,9 @@ in
       users.groups.docker.gid = config.ids.gids.docker;
       systemd.packages = [ cfg.package ];
 
+      # TODO: remove once docker 20.10 is released
+      systemd.enableUnifiedCgroupHierarchy = false;
+
       systemd.services.docker = {
         wantedBy = optional cfg.enableOnBoot "multi-user.target";
         environment = proxy_env;
diff --git a/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix b/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix
index 24de8cf1afbf..3da63078a214 100644
--- a/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix
+++ b/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix
@@ -329,5 +329,24 @@ let self = {
   "20.03".ap-east-1.hvm-ebs = "ami-0d18fdd309cdefa86";
   "20.03".sa-east-1.hvm-ebs = "ami-09859378158ae971d";
 
-  latest = self."20.03";
+  # 20.09.1632.a6a3a368dda
+  "20.09".eu-west-1.hvm-ebs = "ami-01a79d5ce435f4db3";
+  "20.09".eu-west-2.hvm-ebs = "ami-0cbe14f32904e6331";
+  "20.09".eu-west-3.hvm-ebs = "ami-07f493412d6213de6";
+  "20.09".eu-central-1.hvm-ebs = "ami-01d4a0c2248cbfe38";
+  "20.09".eu-north-1.hvm-ebs = "ami-0003f54dd99d68e0f";
+  "20.09".us-east-1.hvm-ebs = "ami-068a62d478710462d";
+  "20.09".us-east-2.hvm-ebs = "ami-01ac677ff61399caa";
+  "20.09".us-west-1.hvm-ebs = "ami-04befdb203b4b17f6";
+  "20.09".us-west-2.hvm-ebs = "ami-0fb7bd4a43261c6b2";
+  "20.09".ca-central-1.hvm-ebs = "ami-06d5ee429f153f856";
+  "20.09".ap-southeast-1.hvm-ebs = "ami-0db0304e23c535b2a";
+  "20.09".ap-southeast-2.hvm-ebs = "ami-045983c4db7e36447";
+  "20.09".ap-northeast-1.hvm-ebs = "ami-0beb18d632cf64e5a";
+  "20.09".ap-northeast-2.hvm-ebs = "ami-0dd0316af578862db";
+  "20.09".ap-south-1.hvm-ebs = "ami-008d15ced81c88aed";
+  "20.09".ap-east-1.hvm-ebs = "ami-071f49713f86ea965";
+  "20.09".sa-east-1.hvm-ebs = "ami-05ded1ae35209b5a8";
+
+  latest = self."20.09";
 }; in self
diff --git a/nixpkgs/nixos/modules/virtualisation/ec2-metadata-fetcher.nix b/nixpkgs/nixos/modules/virtualisation/ec2-metadata-fetcher.nix
index b531787c31a2..dca5c2abd4e0 100644
--- a/nixpkgs/nixos/modules/virtualisation/ec2-metadata-fetcher.nix
+++ b/nixpkgs/nixos/modules/virtualisation/ec2-metadata-fetcher.nix
@@ -1,23 +1,77 @@
-{ targetRoot, wgetExtraOptions }:
+{ curl, targetRoot, wgetExtraOptions }:
+# Note: be very cautious about dependencies, each dependency grows
+# the closure of the initrd. Ideally we would not even require curl,
+# but there is no reasonable way to send an HTTP PUT request without
+# it. Note: do not be fooled: the wget referenced in this script
+# is busybox's wget, not the fully featured one with --method support.
+#
+# Make sure that every package you depend on here is already listed as
+# a channel blocker for both the full-sized and small channels.
+# Otherwise, we risk breaking user deploys in released channels.
+#
+# Also note: OpenStack's metadata service for its instances aims to be
+# compatible with the EC2 IMDS. Where possible, try to keep the set of
+# fetched metadata in sync with ./openstack-metadata-fetcher.nix .
 ''
   metaDir=${targetRoot}etc/ec2-metadata
   mkdir -m 0755 -p "$metaDir"
+  rm -f "$metaDir/*"
 
-  echo "getting EC2 instance metadata..."
+  get_imds_token() {
+    # retry-delay of 1 selected to give the system a second to get going,
+    # but not add a lot to the bootup time
+    ${curl}/bin/curl \
+      -v \
+      --retry 3 \
+      --retry-delay 1 \
+      --fail \
+      -X PUT \
+      --connect-timeout 1 \
+      -H "X-aws-ec2-metadata-token-ttl-seconds: 600" \
+      http://169.254.169.254/latest/api/token
+  }
 
-  if ! [ -e "$metaDir/ami-manifest-path" ]; then
-    wget ${wgetExtraOptions} -O "$metaDir/ami-manifest-path" http://169.254.169.254/1.0/meta-data/ami-manifest-path
-  fi
+  preflight_imds_token() {
+    # retry-delay of 1 selected to give the system a second to get going,
+    # but not add a lot to the bootup time
+    ${curl}/bin/curl \
+      -v \
+      --retry 3 \
+      --retry-delay 1 \
+      --fail \
+      --connect-timeout 1 \
+      -H "X-aws-ec2-metadata-token: $IMDS_TOKEN" \
+      http://169.254.169.254/1.0/meta-data/instance-id
+  }
 
-  if ! [ -e "$metaDir/user-data" ]; then
-    wget ${wgetExtraOptions} -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data && chmod 600 "$metaDir/user-data"
-  fi
+  try=1
+  while [ $try -le 3 ]; do
+    echo "(attempt $try/3) getting an EC2 instance metadata service v2 token..."
+    IMDS_TOKEN=$(get_imds_token) && break
+    try=$((try + 1))
+    sleep 1
+  done
 
-  if ! [ -e "$metaDir/hostname" ]; then
-    wget ${wgetExtraOptions} -O "$metaDir/hostname" http://169.254.169.254/1.0/meta-data/hostname
+  if [ "x$IMDS_TOKEN" == "x" ]; then
+    echo "failed to fetch an IMDS2v token."
   fi
 
-  if ! [ -e "$metaDir/public-keys-0-openssh-key" ]; then
-    wget ${wgetExtraOptions} -O "$metaDir/public-keys-0-openssh-key" http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key
-  fi
+  try=1
+  while [ $try -le 10 ]; do
+    echo "(attempt $try/10) validating the EC2 instance metadata service v2 token..."
+    preflight_imds_token && break
+    try=$((try + 1))
+    sleep 1
+  done
+
+  echo "getting EC2 instance metadata..."
+
+  wget_imds() {
+    wget ${wgetExtraOptions} --header "X-aws-ec2-metadata-token: $IMDS_TOKEN" "$@";
+  }
+
+  wget_imds -O "$metaDir/ami-manifest-path" http://169.254.169.254/1.0/meta-data/ami-manifest-path
+  wget_imds -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data && chmod 600 "$metaDir/user-data"
+  wget_imds -O "$metaDir/hostname" http://169.254.169.254/1.0/meta-data/hostname
+  wget_imds -O "$metaDir/public-keys-0-openssh-key" http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key
 ''
diff --git a/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix b/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix
index 8fbb4efd2019..757d73421b8f 100644
--- a/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix
+++ b/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix
@@ -56,10 +56,10 @@ let
             ip -6 route add $HOST_ADDRESS6 dev eth0
             ip -6 route add default via $HOST_ADDRESS6
           fi
-
-          ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)}
         fi
 
+        ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)}
+
         # Start the regular stage 1 script.
         exec "$1"
       ''
@@ -223,8 +223,8 @@ let
             ${ipcall cfg "ip route" "$LOCAL_ADDRESS" "localAddress"}
             ${ipcall cfg "ip -6 route" "$LOCAL_ADDRESS6" "localAddress6"}
           fi
-          ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)}
         fi
+        ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)}
       ''
   );
 
@@ -614,17 +614,17 @@ in
               '';
             };
 
-		    timeoutStartSec = mkOption {
-		      type = types.str;
-		      default = "1min";
-		      description = ''
-		        Time for the container to start. In case of a timeout,
-		        the container processes get killed.
-		        See <citerefentry><refentrytitle>systemd.time</refentrytitle>
-		        <manvolnum>7</manvolnum></citerefentry>
-		        for more information about the format.
-		       '';
-		    };
+            timeoutStartSec = mkOption {
+              type = types.str;
+              default = "1min";
+              description = ''
+                Time for the container to start. In case of a timeout,
+                the container processes get killed.
+                See <citerefentry><refentrytitle>systemd.time</refentrytitle>
+                <manvolnum>7</manvolnum></citerefentry>
+                for more information about the format.
+               '';
+            };
 
             bindMounts = mkOption {
               type = with types; attrsOf (submodule bindMountOpts);
diff --git a/nixpkgs/nixos/modules/virtualisation/oci-containers.nix b/nixpkgs/nixos/modules/virtualisation/oci-containers.nix
index a46dd65eb491..ee9fe62187d3 100644
--- a/nixpkgs/nixos/modules/virtualisation/oci-containers.nix
+++ b/nixpkgs/nixos/modules/virtualisation/oci-containers.nix
@@ -176,10 +176,10 @@ let
           description = ''
             Define which other containers this one depends on. They will be added to both After and Requires for the unit.
 
-            Use the same name as the attribute under <literal>virtualisation.oci-containers</literal>.
+            Use the same name as the attribute under <literal>virtualisation.oci-containers.containers</literal>.
           '';
           example = literalExample ''
-            virtualisation.oci-containers = {
+            virtualisation.oci-containers.containers = {
               node1 = {};
               node2 = {
                 dependsOn = [ "node1" ];
diff --git a/nixpkgs/nixos/modules/virtualisation/openstack-config.nix b/nixpkgs/nixos/modules/virtualisation/openstack-config.nix
index c2da5d0d2301..d01e0f23aba1 100644
--- a/nixpkgs/nixos/modules/virtualisation/openstack-config.nix
+++ b/nixpkgs/nixos/modules/virtualisation/openstack-config.nix
@@ -3,7 +3,7 @@
 with lib;
 
 let
-  metadataFetcher = import ./ec2-metadata-fetcher.nix {
+  metadataFetcher = import ./openstack-metadata-fetcher.nix {
     targetRoot = "/";
     wgetExtraOptions = "--retry-connrefused";
   };
diff --git a/nixpkgs/nixos/modules/virtualisation/openstack-metadata-fetcher.nix b/nixpkgs/nixos/modules/virtualisation/openstack-metadata-fetcher.nix
new file mode 100644
index 000000000000..8c191397cf9a
--- /dev/null
+++ b/nixpkgs/nixos/modules/virtualisation/openstack-metadata-fetcher.nix
@@ -0,0 +1,21 @@
+{ targetRoot, wgetExtraOptions }:
+
+# OpenStack's metadata service aims to be EC2-compatible. Where
+# possible, try to keep the set of fetched metadata in sync with
+# ./ec2-metadata-fetcher.nix .
+''
+  metaDir=${targetRoot}etc/ec2-metadata
+  mkdir -m 0755 -p "$metaDir"
+  rm -f "$metaDir/*"
+
+  echo "getting instance metadata..."
+
+  wget_imds() {
+    wget ${wgetExtraOptions} "$@"
+  }
+
+  wget_imds -O "$metaDir/ami-manifest-path" http://169.254.169.254/1.0/meta-data/ami-manifest-path
+  wget_imds -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data && chmod 600 "$metaDir/user-data"
+  wget_imds -O "$metaDir/hostname" http://169.254.169.254/1.0/meta-data/hostname
+  wget_imds -O "$metaDir/public-keys-0-openssh-key" http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key
+''
diff --git a/nixpkgs/nixos/modules/virtualisation/qemu-guest-agent.nix b/nixpkgs/nixos/modules/virtualisation/qemu-guest-agent.nix
index 665224e35d8c..6a735f451a7e 100644
--- a/nixpkgs/nixos/modules/virtualisation/qemu-guest-agent.nix
+++ b/nixpkgs/nixos/modules/virtualisation/qemu-guest-agent.nix
@@ -12,6 +12,11 @@ in {
         default = false;
         description = "Whether to enable the qemu guest agent.";
       };
+      package = mkOption {
+        type = types.package;
+        default = pkgs.qemu.ga;
+        description = "The QEMU guest agent package.";
+      };
   };
 
   config = mkIf cfg.enable (
@@ -25,7 +30,7 @@ in {
       systemd.services.qemu-guest-agent = {
         description = "Run the QEMU Guest Agent";
         serviceConfig = {
-          ExecStart = "${pkgs.qemu.ga}/bin/qemu-ga";
+          ExecStart = "${cfg.package}/bin/qemu-ga";
           Restart = "always";
           RestartSec = 0;
         };
diff --git a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
index 42e43f5ee023..447d1f091c8c 100644
--- a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
@@ -14,10 +14,11 @@ with import ../../lib/qemu-flags.nix { inherit pkgs; };
 
 let
 
-  qemu = config.system.build.qemu or pkgs.qemu_test;
 
   cfg = config.virtualisation;
 
+  qemu = cfg.qemu.package;
+
   consoles = lib.concatMapStringsSep " " (c: "console=${c}") cfg.qemu.consoles;
 
   driveOpts = { ... }: {
@@ -189,7 +190,7 @@ let
               '' else ''
               ''}
             '';
-          buildInputs = [ pkgs.utillinux ];
+          buildInputs = [ pkgs.util-linux ];
           QEMU_OPTS = "-nographic -serial stdio -monitor none"
                       + lib.optionalString cfg.useEFIBoot (
                         " -drive if=pflash,format=raw,unit=0,readonly=on,file=${efiFirmware}"
@@ -401,6 +402,14 @@ in
       };
 
     virtualisation.qemu = {
+      package =
+        mkOption {
+          type = types.package;
+          default = pkgs.qemu;
+          example = "pkgs.qemu_test";
+          description = "QEMU package to use.";
+        };
+
       options =
         mkOption {
           type = types.listOf types.unspecified;
@@ -735,16 +744,19 @@ in
         (isEnabled "VIRTIO_PCI")
         (isEnabled "VIRTIO_NET")
         (isEnabled "EXT4_FS")
+        (isEnabled "NET_9P_VIRTIO")
+        (isEnabled "9P_FS")
         (isYes "BLK_DEV")
         (isYes "PCI")
-        (isYes "EXPERIMENTAL")
         (isYes "NETDEVICES")
         (isYes "NET_CORE")
         (isYes "INET")
         (isYes "NETWORK_FILESYSTEMS")
-      ] ++ optional (!cfg.graphics) [
+      ] ++ optionals (!cfg.graphics) [
         (isYes "SERIAL_8250_CONSOLE")
         (isYes "SERIAL_8250")
+      ] ++ optionals (cfg.writableStore) [
+        (isEnabled "OVERLAY_FS")
       ];
 
   };
diff --git a/nixpkgs/nixos/modules/virtualisation/vagrant-guest.nix b/nixpkgs/nixos/modules/virtualisation/vagrant-guest.nix
new file mode 100644
index 000000000000..263b1ebca086
--- /dev/null
+++ b/nixpkgs/nixos/modules/virtualisation/vagrant-guest.nix
@@ -0,0 +1,58 @@
+# Minimal configuration that vagrant depends on
+
+{ config, pkgs, ... }:
+let
+  # Vagrant uses an insecure shared private key by default, but we
+  # don't use the authorizedKeys attribute under users because it should be
+  # removed on first boot and replaced with a random one. This script sets
+  # the correct permissions and installs the temporary key if no
+  # ~/.ssh/authorized_keys exists.
+  install-vagrant-ssh-key = pkgs.writeScriptBin "install-vagrant-ssh-key" ''
+    #!${pkgs.runtimeShell}
+    if [ ! -e ~/.ssh/authorized_keys ]; then
+      mkdir -m 0700 -p ~/.ssh
+      echo "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key" >> ~/.ssh/authorized_keys
+      chmod 0600 ~/.ssh/authorized_keys
+    fi
+  '';
+in
+{
+  # Enable the OpenSSH daemon.
+  services.openssh.enable = true;
+
+  # Packages used by Vagrant
+  environment.systemPackages = with pkgs; [
+    findutils
+    iputils
+    nettools
+    netcat
+    nfs-utils
+    rsync
+  ];
+
+  users.extraUsers.vagrant = {
+    isNormalUser    = true;
+    createHome      = true;
+    description     = "Vagrant user account";
+    extraGroups     = [ "users" "wheel" ];
+    home            = "/home/vagrant";
+    password        = "vagrant";
+    useDefaultShell = true;
+    uid             = 1000;
+  };
+
+  systemd.services.install-vagrant-ssh-key = {
+    description = "Vagrant SSH key install (if needed)";
+    after = [ "fs.target" ];
+    wants = [ "fs.target" ];
+    wantedBy = [ "multi-user.target" ];
+    serviceConfig = {
+      ExecStart = "${install-vagrant-ssh-key}/bin/install-vagrant-ssh-key";
+      User = "vagrant";
+      # So it won't be (needlessly) restarted:
+      RemainAfterExit = true;
+    };
+  };
+
+  security.sudo.wheelNeedsPassword = false;
+}
diff --git a/nixpkgs/nixos/modules/virtualisation/vagrant-virtualbox-image.nix b/nixpkgs/nixos/modules/virtualisation/vagrant-virtualbox-image.nix
new file mode 100644
index 000000000000..2a921894ab61
--- /dev/null
+++ b/nixpkgs/nixos/modules/virtualisation/vagrant-virtualbox-image.nix
@@ -0,0 +1,60 @@
+# Vagrant + VirtualBox
+
+{ config, pkgs, ... }:
+
+{
+  imports = [
+    ./vagrant-guest.nix
+    ./virtualbox-image.nix
+  ];
+
+  virtualbox.params = {
+    audio = "none";
+    audioin = "off";
+    audioout = "off";
+    usb = "off";
+    usbehci = "off";
+  };
+  sound.enable = false;
+  documentation.man.enable = false;
+  documentation.nixos.enable = false;
+
+  users.extraUsers.vagrant.extraGroups = [ "vboxsf" ];
+
+  # generate the box v1 format which is much easier to generate
+  # https://www.vagrantup.com/docs/boxes/format.html
+  system.build.vagrantVirtualbox = pkgs.runCommand
+    "virtualbox-vagrant.box"
+    {}
+    ''
+      mkdir workdir
+      cd workdir
+
+      # 1. create that metadata.json file
+      echo '{"provider":"virtualbox"}' > metadata.json
+
+      # 2. create a default Vagrantfile config
+      cat <<VAGRANTFILE > Vagrantfile
+      Vagrant.configure("2") do |config|
+        config.vm.base_mac = "0800275F0936"
+      end
+      VAGRANTFILE
+
+      # 3. add the exported VM files
+      tar xvf ${config.system.build.virtualBoxOVA}/*.ova
+
+      # 4. move the ovf to the fixed location
+      mv *.ovf box.ovf
+
+      # 5. generate OVF manifest file
+      rm *.mf
+      touch box.mf
+      for fname in *; do
+        checksum=$(sha256sum $fname | cut -d' ' -f 1)
+        echo "SHA256($fname)= $checksum" >> box.mf
+      done
+
+      # 6. compress everything back together
+      tar --owner=0 --group=0 --sort=name --numeric-owner -czf $out .
+    '';
+}
diff --git a/nixpkgs/nixos/modules/virtualisation/xen-dom0.nix b/nixpkgs/nixos/modules/virtualisation/xen-dom0.nix
index 7b2a66c43489..5ad647769bbd 100644
--- a/nixpkgs/nixos/modules/virtualisation/xen-dom0.nix
+++ b/nixpkgs/nixos/modules/virtualisation/xen-dom0.nix
@@ -201,8 +201,8 @@ in
       ''
         if [ -d /proc/xen ]; then
             ${pkgs.kmod}/bin/modprobe xenfs 2> /dev/null
-            ${pkgs.utillinux}/bin/mountpoint -q /proc/xen || \
-                ${pkgs.utillinux}/bin/mount -t xenfs none /proc/xen
+            ${pkgs.util-linux}/bin/mountpoint -q /proc/xen || \
+                ${pkgs.util-linux}/bin/mount -t xenfs none /proc/xen
         fi
       '';