about summary refs log tree commit diff
path: root/nixpkgs/nixos
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2024-02-13 12:25:07 +0100
committerAlyssa Ross <hi@alyssa.is>2024-02-13 12:25:07 +0100
commita5e1520e4538e29ecfbd4b168306f890566d7bfd (patch)
tree28099c268b5d4b1e33c2b29f0714c45f0b961382 /nixpkgs/nixos
parent822f7c15c04567fbdc27020e862ea2b70cfbf8eb (diff)
parent3560d1c8269d0091b9aae10731b5e85274b7bbc1 (diff)
downloadnixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.gz
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.bz2
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.lz
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.xz
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.zst
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.zip
Merge branch 'nixos-unstable-small' of https://github.com/NixOS/nixpkgs
Conflicts:
	nixpkgs/nixos/modules/services/mail/rss2email.nix
	nixpkgs/pkgs/build-support/go/module.nix
Diffstat (limited to 'nixpkgs/nixos')
-rw-r--r--nixpkgs/nixos/doc/manual/configuration/file-systems.chapter.md1
-rw-r--r--nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md18
-rw-r--r--nixpkgs/nixos/doc/manual/configuration/overlayfs.section.md27
-rw-r--r--nixpkgs/nixos/doc/manual/configuration/profiles.chapter.md1
-rw-r--r--nixpkgs/nixos/doc/manual/configuration/profiles/perlless.section.md11
-rw-r--r--nixpkgs/nixos/doc/manual/configuration/sshfs-file-systems.section.md2
-rw-r--r--nixpkgs/nixos/doc/manual/configuration/user-mgmt.chapter.md15
-rw-r--r--nixpkgs/nixos/doc/manual/contributing-to-this-manual.chapter.md2
-rw-r--r--nixpkgs/nixos/doc/manual/development/etc-overlay.section.md36
-rw-r--r--nixpkgs/nixos/doc/manual/development/option-types.section.md2
-rw-r--r--nixpkgs/nixos/doc/manual/development/what-happens-during-a-system-switch.chapter.md1
-rw-r--r--nixpkgs/nixos/doc/manual/development/writing-documentation.chapter.md64
-rw-r--r--nixpkgs/nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md17
-rw-r--r--nixpkgs/nixos/doc/manual/release-notes/rl-2405.section.md155
-rw-r--r--nixpkgs/nixos/lib/eval-config.nix1
-rw-r--r--nixpkgs/nixos/lib/systemd-lib.nix10
-rw-r--r--nixpkgs/nixos/lib/systemd-unit-options.nix17
-rw-r--r--nixpkgs/nixos/lib/test-driver/test_driver/machine.py26
-rw-r--r--nixpkgs/nixos/lib/utils.nix1
-rw-r--r--nixpkgs/nixos/maintainers/scripts/ec2/README.md7
-rw-r--r--nixpkgs/nixos/maintainers/scripts/ec2/amazon-image.nix2
-rw-r--r--nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image-inner.nix18
-rw-r--r--nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image.nix18
-rw-r--r--nixpkgs/nixos/modules/config/no-x-libs.nix2
-rw-r--r--nixpkgs/nixos/modules/config/shells-environment.nix3
-rw-r--r--nixpkgs/nixos/modules/config/users-groups.nix10
-rw-r--r--nixpkgs/nixos/modules/hardware/corectrl.nix8
-rw-r--r--nixpkgs/nixos/modules/image/repart-image.nix38
-rw-r--r--nixpkgs/nixos/modules/image/repart.nix86
-rw-r--r--nixpkgs/nixos/modules/misc/ids.nix4
-rw-r--r--nixpkgs/nixos/modules/misc/version.nix172
-rw-r--r--nixpkgs/nixos/modules/module-list.nix27
-rw-r--r--nixpkgs/nixos/modules/profiles/hardened.nix9
-rw-r--r--nixpkgs/nixos/modules/profiles/installation-device.nix3
-rw-r--r--nixpkgs/nixos/modules/profiles/perlless.nix31
-rw-r--r--nixpkgs/nixos/modules/programs/alvr.nix35
-rw-r--r--nixpkgs/nixos/modules/programs/chromium.nix48
-rw-r--r--nixpkgs/nixos/modules/programs/gamemode.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/light.nix50
-rw-r--r--nixpkgs/nixos/modules/programs/mouse-actions.nix15
-rw-r--r--nixpkgs/nixos/modules/programs/nautilus-open-any-terminal.nix36
-rw-r--r--nixpkgs/nixos/modules/programs/regreet.nix16
-rw-r--r--nixpkgs/nixos/modules/programs/ssh.nix1
-rw-r--r--nixpkgs/nixos/modules/programs/tsm-client.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/wayland/hyprland.nix (renamed from nixpkgs/nixos/modules/programs/hyprland.nix)0
-rw-r--r--nixpkgs/nixos/modules/rename.nix1
-rw-r--r--nixpkgs/nixos/modules/security/acme/default.nix16
-rw-r--r--nixpkgs/nixos/modules/security/pam.nix18
-rw-r--r--nixpkgs/nixos/modules/security/pam_usb.nix51
-rw-r--r--nixpkgs/nixos/modules/security/wrappers/wrapper.c7
-rw-r--r--nixpkgs/nixos/modules/services/amqp/rabbitmq.nix21
-rw-r--r--nixpkgs/nixos/modules/services/audio/gmediarender.nix1
-rw-r--r--nixpkgs/nixos/modules/services/audio/jmusicbot.nix1
-rw-r--r--nixpkgs/nixos/modules/services/audio/mopidy.nix7
-rw-r--r--nixpkgs/nixos/modules/services/audio/navidrome.nix1
-rw-r--r--nixpkgs/nixos/modules/services/audio/spotifyd.nix1
-rw-r--r--nixpkgs/nixos/modules/services/audio/ympd.nix1
-rw-r--r--nixpkgs/nixos/modules/services/backup/tsm.nix2
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix9
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/buildbot/master.nix2
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/gitea-actions-runner.nix1
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/github-runner.nix25
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/github-runner/options.nix456
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/github-runner/service.nix511
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/github-runners.nix62
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix1
-rw-r--r--nixpkgs/nixos/modules/services/databases/etcd.nix (renamed from nixpkgs/nixos/modules/services/misc/etcd.nix)32
-rw-r--r--nixpkgs/nixos/modules/services/databases/firebird.nix2
-rw-r--r--nixpkgs/nixos/modules/services/databases/lldap.nix1
-rw-r--r--nixpkgs/nixos/modules/services/databases/neo4j.nix77
-rw-r--r--nixpkgs/nixos/modules/services/databases/openldap.nix1
-rw-r--r--nixpkgs/nixos/modules/services/databases/tigerbeetle.md33
-rw-r--r--nixpkgs/nixos/modules/services/databases/tigerbeetle.nix115
-rw-r--r--nixpkgs/nixos/modules/services/desktops/geoclue2.nix2
-rw-r--r--nixpkgs/nixos/modules/services/development/livebook.md24
-rw-r--r--nixpkgs/nixos/modules/services/development/livebook.nix101
-rw-r--r--nixpkgs/nixos/modules/services/editors/emacs.nix21
-rw-r--r--nixpkgs/nixos/modules/services/games/archisteamfarm.nix (renamed from nixpkgs/nixos/modules/services/games/asf.nix)107
-rw-r--r--nixpkgs/nixos/modules/services/hardware/acpid.nix1
-rw-r--r--nixpkgs/nixos/modules/services/hardware/fwupd.nix26
-rw-r--r--nixpkgs/nixos/modules/services/hardware/handheld-daemon.nix44
-rw-r--r--nixpkgs/nixos/modules/services/hardware/pcscd.nix6
-rw-r--r--nixpkgs/nixos/modules/services/hardware/ratbagd.nix8
-rw-r--r--nixpkgs/nixos/modules/services/home-automation/esphome.nix12
-rw-r--r--nixpkgs/nixos/modules/services/home-automation/evcc.nix1
-rw-r--r--nixpkgs/nixos/modules/services/home-automation/govee2mqtt.nix90
-rw-r--r--nixpkgs/nixos/modules/services/home-automation/home-assistant.nix43
-rw-r--r--nixpkgs/nixos/modules/services/logging/journaldriver.nix1
-rw-r--r--nixpkgs/nixos/modules/services/mail/dovecot.nix158
-rw-r--r--nixpkgs/nixos/modules/services/mail/mlmmj.nix12
-rw-r--r--nixpkgs/nixos/modules/services/mail/postfixadmin.nix6
-rw-r--r--nixpkgs/nixos/modules/services/mail/roundcube.nix1
-rw-r--r--nixpkgs/nixos/modules/services/mail/sympa.nix2
-rw-r--r--nixpkgs/nixos/modules/services/mail/zeyple.nix6
-rw-r--r--nixpkgs/nixos/modules/services/matrix/hebbot.nix78
-rw-r--r--nixpkgs/nixos/modules/services/matrix/synapse.md5
-rw-r--r--nixpkgs/nixos/modules/services/matrix/synapse.nix168
-rw-r--r--nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix1
-rw-r--r--nixpkgs/nixos/modules/services/misc/bcg.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/domoticz.nix1
-rw-r--r--nixpkgs/nixos/modules/services/misc/etesync-dav.nix1
-rw-r--r--nixpkgs/nixos/modules/services/misc/gitea.nix5
-rw-r--r--nixpkgs/nixos/modules/services/misc/gitlab.nix14
-rw-r--r--nixpkgs/nixos/modules/services/misc/jellyfin.nix190
-rw-r--r--nixpkgs/nixos/modules/services/misc/lidarr.nix7
-rw-r--r--nixpkgs/nixos/modules/services/misc/mediatomb.nix1
-rw-r--r--nixpkgs/nixos/modules/services/misc/metabase.nix1
-rw-r--r--nixpkgs/nixos/modules/services/misc/moonraker.nix23
-rw-r--r--nixpkgs/nixos/modules/services/misc/nix-gc.nix28
-rw-r--r--nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/ollama.nix8
-rw-r--r--nixpkgs/nixos/modules/services/misc/packagekit.nix4
-rw-r--r--nixpkgs/nixos/modules/services/misc/paperless.nix27
-rw-r--r--nixpkgs/nixos/modules/services/misc/portunus.nix100
-rw-r--r--nixpkgs/nixos/modules/services/misc/radarr.nix7
-rw-r--r--nixpkgs/nixos/modules/services/misc/readarr.nix7
-rw-r--r--nixpkgs/nixos/modules/services/misc/sourcehut/default.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/taskserver/helper-tool.py34
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/alerta.nix7
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/kapacitor.nix6
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix1
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/munin.nix24
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/osquery.nix8
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/alertmanager.nix1
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix39
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix42
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/restic.nix131
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix1
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/riemann-dash.nix7
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/rustdesk-server.nix113
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/teamviewer.nix1
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/telegraf.nix1
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/watchdogd.nix131
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix5
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/zabbix-server.nix5
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/cachefilesd.nix8
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/ceph.nix20
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/kbfs.nix7
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/kubo.nix13
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix1
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/samba.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/aria2.nix15
-rw-r--r--nixpkgs/nixos/modules/services/networking/bird.nix9
-rw-r--r--nixpkgs/nixos/modules/services/networking/bitcoind.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/charybdis.nix6
-rw-r--r--nixpkgs/nixos/modules/services/networking/cloudflared.nix7
-rw-r--r--nixpkgs/nixos/modules/services/networking/dante.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/dhcpcd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/dnsdist.nix143
-rw-r--r--nixpkgs/nixos/modules/services/networking/ergo.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/expressvpn.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/headscale.nix13
-rw-r--r--nixpkgs/nixos/modules/services/networking/hostapd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/ircd-hybrid/default.nix3
-rw-r--r--nixpkgs/nixos/modules/services/networking/ivpn.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/jibri/default.nix25
-rw-r--r--nixpkgs/nixos/modules/services/networking/jicofo.nix15
-rw-r--r--nixpkgs/nixos/modules/services/networking/jitsi-videobridge.nix15
-rw-r--r--nixpkgs/nixos/modules/services/networking/kea.nix7
-rw-r--r--nixpkgs/nixos/modules/services/networking/keepalived/default.nix9
-rw-r--r--nixpkgs/nixos/modules/services/networking/knot.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/kresd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/mosquitto.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/murmur.nix23
-rw-r--r--nixpkgs/nixos/modules/services/networking/nbd.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/netbird.md56
-rw-r--r--nixpkgs/nixos/modules/services/networking/netbird.nix203
-rw-r--r--nixpkgs/nixos/modules/services/networking/nftables.nix30
-rw-r--r--nixpkgs/nixos/modules/services/networking/ocserv.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/pleroma.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/pyload.nix166
-rw-r--r--nixpkgs/nixos/modules/services/networking/rosenpass.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/rxe.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/seafile.nix278
-rw-r--r--nixpkgs/nixos/modules/services/networking/soju.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix14
-rw-r--r--nixpkgs/nixos/modules/services/networking/strongswan.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/syncplay.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/tailscale.nix3
-rw-r--r--nixpkgs/nixos/modules/services/networking/wasabibackend.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/znc/default.nix1
-rw-r--r--nixpkgs/nixos/modules/services/security/bitwarden-directory-connector-cli.nix64
-rw-r--r--nixpkgs/nixos/modules/services/security/certmgr.nix1
-rw-r--r--nixpkgs/nixos/modules/services/security/clamav.nix2
-rw-r--r--nixpkgs/nixos/modules/services/security/intune.nix32
-rw-r--r--nixpkgs/nixos/modules/services/security/kanidm.nix15
-rw-r--r--nixpkgs/nixos/modules/services/security/oauth2_proxy.nix1
-rw-r--r--nixpkgs/nixos/modules/services/system/cachix-agent/default.nix1
-rw-r--r--nixpkgs/nixos/modules/services/system/cachix-watch-store.nix1
-rw-r--r--nixpkgs/nixos/modules/services/system/cloud-init.nix5
-rw-r--r--nixpkgs/nixos/modules/services/system/dbus.nix1
-rw-r--r--nixpkgs/nixos/modules/services/system/systemd-lock-handler.md47
-rw-r--r--nixpkgs/nixos/modules/services/system/systemd-lock-handler.nix27
-rw-r--r--nixpkgs/nixos/modules/services/torrent/deluge.nix30
-rw-r--r--nixpkgs/nixos/modules/services/video/epgstation/default.nix30
-rw-r--r--nixpkgs/nixos/modules/services/video/frigate.nix135
-rw-r--r--nixpkgs/nixos/modules/services/video/go2rtc/default.nix1
-rw-r--r--nixpkgs/nixos/modules/services/video/mirakurun.nix7
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/akkoma.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/alps.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/bookstack.nix33
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/c2fmzq-server.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/code-server.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/freshrss.nix7
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/healthchecks.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/lemmy.nix3
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/mastodon.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/mattermost.nix4
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/moodle.nix7
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/netbox.nix20
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/nextcloud-notify_push.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/nextcloud.md2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/nextcloud.nix262
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/nifi.nix13
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/openvscode-server.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/peering-manager.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/photoprism.nix5
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/pretalx.nix415
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/restya-board.nix380
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/suwayomi-server.md108
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/suwayomi-server.nix215
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/tt-rss.nix19
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/writefreely.nix6
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/youtrack.md30
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/youtrack.nix239
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/agate.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/mighttpd2.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/minio.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/nginx/default.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/traefik.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/ttyd.nix3
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/zope2.nix2
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/budgie.nix4
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/deepin.nix11
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/phosh.nix15
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix8
-rw-r--r--nixpkgs/nixos/modules/services/x11/xserver.nix4
-rw-r--r--nixpkgs/nixos/modules/system/boot/clevis.md6
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl6
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py89
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix17
-rw-r--r--nixpkgs/nixos/modules/system/boot/luksroot.nix4
-rw-r--r--nixpkgs/nixos/modules/system/boot/networkd.nix6
-rw-r--r--nixpkgs/nixos/modules/system/boot/resolved.nix24
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-1-init.sh11
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd.nix18
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd/initrd.nix4
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd/journald.nix4
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd/sysupdate.nix4
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd/sysusers.nix169
-rw-r--r--nixpkgs/nixos/modules/system/boot/uki.nix85
-rw-r--r--nixpkgs/nixos/modules/system/etc/build-composefs-dump.py217
-rwxr-xr-xnixpkgs/nixos/modules/system/etc/check-build-composefs-dump.sh8
-rw-r--r--nixpkgs/nixos/modules/system/etc/etc-activation.nix98
-rw-r--r--nixpkgs/nixos/modules/system/etc/etc.nix116
-rw-r--r--nixpkgs/nixos/modules/tasks/auto-upgrade.nix12
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix9
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/overlayfs.nix144
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/sshfs.nix7
-rw-r--r--nixpkgs/nixos/modules/testing/test-instrumentation.nix5
-rw-r--r--nixpkgs/nixos/modules/virtualisation/amazon-image.nix2
-rw-r--r--nixpkgs/nixos/modules/virtualisation/amazon-init.nix1
-rw-r--r--nixpkgs/nixos/modules/virtualisation/incus.nix5
-rw-r--r--nixpkgs/nixos/modules/virtualisation/libvirtd.nix1
-rw-r--r--nixpkgs/nixos/modules/virtualisation/oci-containers.nix8
-rw-r--r--nixpkgs/nixos/modules/virtualisation/podman/default.nix33
-rw-r--r--nixpkgs/nixos/modules/virtualisation/qemu-vm.nix39
-rw-r--r--nixpkgs/nixos/tests/3proxy.nix1
-rw-r--r--nixpkgs/nixos/tests/acme.nix1
-rw-r--r--nixpkgs/nixos/tests/activation/etc-overlay-immutable.nix30
-rw-r--r--nixpkgs/nixos/tests/activation/etc-overlay-mutable.nix30
-rw-r--r--nixpkgs/nixos/tests/activation/perlless.nix24
-rw-r--r--nixpkgs/nixos/tests/adguardhome.nix1
-rw-r--r--nixpkgs/nixos/tests/all-tests.nix22
-rw-r--r--nixpkgs/nixos/tests/appliance-repart-image.nix35
-rw-r--r--nixpkgs/nixos/tests/ayatana-indicators.nix54
-rw-r--r--nixpkgs/nixos/tests/babeld.nix4
-rw-r--r--nixpkgs/nixos/tests/bittorrent.nix4
-rw-r--r--nixpkgs/nixos/tests/budgie.nix7
-rw-r--r--nixpkgs/nixos/tests/buildbot.nix2
-rw-r--r--nixpkgs/nixos/tests/ceph-multi-node.nix8
-rw-r--r--nixpkgs/nixos/tests/ceph-single-node-bluestore.nix8
-rw-r--r--nixpkgs/nixos/tests/ceph-single-node.nix29
-rw-r--r--nixpkgs/nixos/tests/cinnamon-wayland.nix2
-rw-r--r--nixpkgs/nixos/tests/cloud-init.nix1
-rw-r--r--nixpkgs/nixos/tests/corerad.nix2
-rw-r--r--nixpkgs/nixos/tests/curl-impersonate.nix2
-rw-r--r--nixpkgs/nixos/tests/dnsdist.nix137
-rw-r--r--nixpkgs/nixos/tests/dolibarr.nix2
-rw-r--r--nixpkgs/nixos/tests/elk.nix6
-rw-r--r--nixpkgs/nixos/tests/ferm.nix2
-rw-r--r--nixpkgs/nixos/tests/filesystems-overlayfs.nix89
-rw-r--r--nixpkgs/nixos/tests/freetube.nix2
-rw-r--r--nixpkgs/nixos/tests/frigate.nix9
-rw-r--r--nixpkgs/nixos/tests/gitdaemon.nix3
-rw-r--r--nixpkgs/nixos/tests/gitlab.nix2
-rw-r--r--nixpkgs/nixos/tests/gnome-extensions.nix2
-rw-r--r--nixpkgs/nixos/tests/guix/publish.nix1
-rw-r--r--nixpkgs/nixos/tests/haproxy.nix109
-rw-r--r--nixpkgs/nixos/tests/hostname.nix1
-rw-r--r--nixpkgs/nixos/tests/incus/container.nix10
-rw-r--r--nixpkgs/nixos/tests/incus/lxd-to-incus.nix6
-rw-r--r--nixpkgs/nixos/tests/incus/virtual-machine.nix2
-rw-r--r--nixpkgs/nixos/tests/installed-tests/fwupd.nix9
-rw-r--r--nixpkgs/nixos/tests/installer.nix3
-rw-r--r--nixpkgs/nixos/tests/intune.nix56
-rw-r--r--nixpkgs/nixos/tests/kanidm.nix1
-rw-r--r--nixpkgs/nixos/tests/keepalived.nix3
-rw-r--r--nixpkgs/nixos/tests/kernel-generic.nix3
-rw-r--r--nixpkgs/nixos/tests/kernel-rust.nix43
-rw-r--r--nixpkgs/nixos/tests/lemmy.nix2
-rw-r--r--nixpkgs/nixos/tests/livebook-service.nix10
-rw-r--r--nixpkgs/nixos/tests/miriway.nix2
-rw-r--r--nixpkgs/nixos/tests/netbird.nix2
-rw-r--r--nixpkgs/nixos/tests/networking.nix3
-rw-r--r--nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix2
-rw-r--r--nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix2
-rw-r--r--nixpkgs/nixos/tests/nfs/kerberos.nix1
-rw-r--r--nixpkgs/nixos/tests/nginx-moreheaders.nix37
-rw-r--r--nixpkgs/nixos/tests/nixops/default.nix6
-rw-r--r--nixpkgs/nixos/tests/nixos-rebuild-target-host.nix5
-rw-r--r--nixpkgs/nixos/tests/nvmetcfg.nix43
-rw-r--r--nixpkgs/nixos/tests/oci-containers.nix5
-rw-r--r--nixpkgs/nixos/tests/opensmtpd-rspamd.nix1
-rw-r--r--nixpkgs/nixos/tests/opensmtpd.nix1
-rw-r--r--nixpkgs/nixos/tests/owncast.nix2
-rw-r--r--nixpkgs/nixos/tests/podman/default.nix2
-rw-r--r--nixpkgs/nixos/tests/pomerium.nix4
-rw-r--r--nixpkgs/nixos/tests/postgis.nix1
-rw-r--r--nixpkgs/nixos/tests/prometheus-exporters.nix80
-rw-r--r--nixpkgs/nixos/tests/pyload.nix33
-rw-r--r--nixpkgs/nixos/tests/qemu-vm-restrictnetwork.nix2
-rw-r--r--nixpkgs/nixos/tests/rss2email.nix1
-rw-r--r--nixpkgs/nixos/tests/sane.nix85
-rw-r--r--nixpkgs/nixos/tests/ssh-audit.nix1
-rw-r--r--nixpkgs/nixos/tests/suwayomi-server.nix46
-rw-r--r--nixpkgs/nixos/tests/systemd-lock-handler.nix56
-rw-r--r--nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix3
-rw-r--r--nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix8
-rw-r--r--nixpkgs/nixos/tests/systemd-nspawn.nix1
-rw-r--r--nixpkgs/nixos/tests/systemd-sysupdate.nix14
-rw-r--r--nixpkgs/nixos/tests/systemd-sysusers-immutable.nix64
-rw-r--r--nixpkgs/nixos/tests/systemd-sysusers-mutable.nix71
-rw-r--r--nixpkgs/nixos/tests/tayga.nix2
-rw-r--r--nixpkgs/nixos/tests/trafficserver.nix1
-rw-r--r--nixpkgs/nixos/tests/tsm-client-gui.nix2
-rw-r--r--nixpkgs/nixos/tests/ulogd/ulogd.py1
-rw-r--r--nixpkgs/nixos/tests/upnp.nix2
-rw-r--r--nixpkgs/nixos/tests/uptermd.nix1
-rw-r--r--nixpkgs/nixos/tests/urn-timer.nix26
-rw-r--r--nixpkgs/nixos/tests/watchdogd.nix22
-rw-r--r--nixpkgs/nixos/tests/web-apps/netbox-upgrade.nix4
-rw-r--r--nixpkgs/nixos/tests/web-apps/pretalx.nix31
-rw-r--r--nixpkgs/nixos/tests/web-servers/stargazer.nix108
-rw-r--r--nixpkgs/nixos/tests/web-servers/ttyd.nix19
-rw-r--r--nixpkgs/nixos/tests/zfs.nix25
-rw-r--r--nixpkgs/nixos/tests/zigbee2mqtt.nix13
-rw-r--r--nixpkgs/nixos/tests/zrepl.nix1
360 files changed, 7822 insertions, 2723 deletions
diff --git a/nixpkgs/nixos/doc/manual/configuration/file-systems.chapter.md b/nixpkgs/nixos/doc/manual/configuration/file-systems.chapter.md
index aca978be064d..3dfdd20ac33e 100644
--- a/nixpkgs/nixos/doc/manual/configuration/file-systems.chapter.md
+++ b/nixpkgs/nixos/doc/manual/configuration/file-systems.chapter.md
@@ -39,4 +39,5 @@ and non-critical by adding `options = [ "nofail" ];`.
 ```{=include=} sections
 luks-file-systems.section.md
 sshfs-file-systems.section.md
+overlayfs.section.md
 ```
diff --git a/nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md b/nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md
index 9d1b2bc2f9b8..31d8d1a7d0cf 100644
--- a/nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md
+++ b/nixpkgs/nixos/doc/manual/configuration/linux-kernel.chapter.md
@@ -92,6 +92,24 @@ To use your custom kernel package in your NixOS configuration, set
 boot.kernelPackages = pkgs.linuxPackagesFor yourCustomKernel;
 ```
 
+## Rust {#sec-linux-rust}
+
+The Linux kernel does not have Rust language support enabled by
+default. For kernel versions 6.7 or newer, experimental Rust support
+can be enabled. In a NixOS configuration, set:
+
+```nix
+boot.kernelPatches = [
+  {
+    name = "Rust Support";
+    patch = null;
+    features = {
+      rust = true;
+    };
+  }
+];
+```
+
 ## Developing kernel modules {#sec-linux-config-developing-modules}
 
 This section was moved to the [Nixpkgs manual](https://nixos.org/nixpkgs/manual#sec-linux-kernel-developing-modules).
diff --git a/nixpkgs/nixos/doc/manual/configuration/overlayfs.section.md b/nixpkgs/nixos/doc/manual/configuration/overlayfs.section.md
new file mode 100644
index 000000000000..592fb7c2e6f7
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/configuration/overlayfs.section.md
@@ -0,0 +1,27 @@
+# Overlayfs {#sec-overlayfs}
+
+NixOS offers a convenient abstraction to create both read-only as well writable
+overlays.
+
+```nix
+fileSystems = {
+  "/writable-overlay" = {
+    overlay = {
+      lowerdir = [ writableOverlayLowerdir ];
+      upperdir = "/.rw-writable-overlay/upper";
+      workdir = "/.rw-writable-overlay/work";
+    };
+    # Mount the writable overlay in the initrd.
+    neededForBoot = true;
+  };
+  "/readonly-overlay".overlay.lowerdir = [
+    writableOverlayLowerdir
+    writableOverlayLowerdir2
+  ];
+};
+```
+
+If `upperdir` and `workdir` are not null, they will be created before the
+overlay is mounted.
+
+To mount an overlay as read-only, you need to provide at least two `lowerdir`s.
diff --git a/nixpkgs/nixos/doc/manual/configuration/profiles.chapter.md b/nixpkgs/nixos/doc/manual/configuration/profiles.chapter.md
index 9f1f48f742ac..9f6c11b0d59d 100644
--- a/nixpkgs/nixos/doc/manual/configuration/profiles.chapter.md
+++ b/nixpkgs/nixos/doc/manual/configuration/profiles.chapter.md
@@ -29,6 +29,7 @@ profiles/graphical.section.md
 profiles/hardened.section.md
 profiles/headless.section.md
 profiles/installation-device.section.md
+profiles/perlless.section.md
 profiles/minimal.section.md
 profiles/qemu-guest.section.md
 ```
diff --git a/nixpkgs/nixos/doc/manual/configuration/profiles/perlless.section.md b/nixpkgs/nixos/doc/manual/configuration/profiles/perlless.section.md
new file mode 100644
index 000000000000..bf055971cfc4
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/configuration/profiles/perlless.section.md
@@ -0,0 +1,11 @@
+# Perlless {#sec-perlless}
+
+::: {.warning}
+If you enable this profile, you will NOT be able to switch to a new
+configuration and thus you will not be able to rebuild your system with
+nixos-rebuild!
+:::
+
+Render your system completely perlless (i.e. without the perl interpreter). This
+includes a mechanism so that your build fails if it contains a Nix store path
+that references the string "perl".
diff --git a/nixpkgs/nixos/doc/manual/configuration/sshfs-file-systems.section.md b/nixpkgs/nixos/doc/manual/configuration/sshfs-file-systems.section.md
index d8c9dea6c337..e2e37454b7ea 100644
--- a/nixpkgs/nixos/doc/manual/configuration/sshfs-file-systems.section.md
+++ b/nixpkgs/nixos/doc/manual/configuration/sshfs-file-systems.section.md
@@ -38,8 +38,6 @@ The file system can be configured in NixOS via the usual [fileSystems](#opt-file
 Here's a typical setup:
 ```nix
 {
-  system.fsPackages = [ pkgs.sshfs ];
-
   fileSystems."/mnt/my-dir" = {
     device = "my-user@example.com:/my-dir/";
     fsType = "sshfs";
diff --git a/nixpkgs/nixos/doc/manual/configuration/user-mgmt.chapter.md b/nixpkgs/nixos/doc/manual/configuration/user-mgmt.chapter.md
index b35b38f6e964..71d61ce4c641 100644
--- a/nixpkgs/nixos/doc/manual/configuration/user-mgmt.chapter.md
+++ b/nixpkgs/nixos/doc/manual/configuration/user-mgmt.chapter.md
@@ -89,3 +89,18 @@ A user can be deleted using `userdel`:
 The flag `-r` deletes the user's home directory. Accounts can be
 modified using `usermod`. Unix groups can be managed using `groupadd`,
 `groupmod` and `groupdel`.
+
+## Create users and groups with `systemd-sysusers` {#sec-systemd-sysusers}
+
+::: {.note}
+This is experimental.
+:::
+
+Instead of using a custom perl script to create users and groups, you can use
+systemd-sysusers:
+
+```nix
+systemd.sysusers.enable = true;
+```
+
+The primary benefit of this is to remove a dependency on perl.
diff --git a/nixpkgs/nixos/doc/manual/contributing-to-this-manual.chapter.md b/nixpkgs/nixos/doc/manual/contributing-to-this-manual.chapter.md
index 6245280e30f0..83e4773e6866 100644
--- a/nixpkgs/nixos/doc/manual/contributing-to-this-manual.chapter.md
+++ b/nixpkgs/nixos/doc/manual/contributing-to-this-manual.chapter.md
@@ -1,6 +1,6 @@
 # Contributing to this manual {#chap-contributing}
 
-The [DocBook] and CommonMark sources of the NixOS manual are in the [nixos/doc/manual](https://github.com/NixOS/nixpkgs/tree/master/nixos/doc/manual) subdirectory of the [Nixpkgs](https://github.com/NixOS/nixpkgs) repository.
+The sources of the NixOS manual are in the [nixos/doc/manual](https://github.com/NixOS/nixpkgs/tree/master/nixos/doc/manual) subdirectory of the [Nixpkgs](https://github.com/NixOS/nixpkgs) repository.
 This manual uses the [Nixpkgs manual syntax](https://nixos.org/manual/nixpkgs/unstable/#sec-contributing-markup).
 
 You can quickly check your edits with the following:
diff --git a/nixpkgs/nixos/doc/manual/development/etc-overlay.section.md b/nixpkgs/nixos/doc/manual/development/etc-overlay.section.md
new file mode 100644
index 000000000000..e6f6d8d4ca1e
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/etc-overlay.section.md
@@ -0,0 +1,36 @@
+# `/etc` via overlay filesystem {#sec-etc-overlay}
+
+::: {.note}
+This is experimental and requires a kernel version >= 6.6 because it uses
+new overlay features and relies on the new mount API.
+:::
+
+Instead of using a custom perl script to activate `/etc`, you activate it via an
+overlay filesystem:
+
+```nix
+system.etc.overlay.enable = true;
+```
+
+Using an overlay has two benefits:
+
+1. it removes a dependency on perl
+2. it makes activation faster (up to a few seconds)
+
+By default, the `/etc` overlay is mounted writable (i.e. there is a writable
+upper layer). However, you can also mount `/etc` immutably (i.e. read-only) by
+setting:
+
+```nix
+system.etc.overlay.mutable = false;
+```
+
+The overlay is atomically replaced during system switch. However, files that
+have been modified will NOT be overwritten. This is the biggest change compared
+to the perl-based system.
+
+If you manually make changes to `/etc` on your system and then switch to a new
+configuration where `system.etc.overlay.mutable = false;`, you will not be able
+to see the previously made changes in `/etc` anymore. However the changes are
+not completely gone, they are still in the upperdir of the previous overlay in
+`/.rw-etc/upper`.
diff --git a/nixpkgs/nixos/doc/manual/development/option-types.section.md b/nixpkgs/nixos/doc/manual/development/option-types.section.md
index f9c7ac80018e..04edf99e70b0 100644
--- a/nixpkgs/nixos/doc/manual/development/option-types.section.md
+++ b/nixpkgs/nixos/doc/manual/development/option-types.section.md
@@ -326,7 +326,7 @@ Composed types are types that take a type as parameter. `listOf
 `types.uniq` *`t`*
 
 :   Ensures that type *`t`* cannot be merged. It is used to ensure option
-    definitions are declared only once.
+    definitions are provided only once.
 
 `types.unique` `{ message = m }` *`t`*
 
diff --git a/nixpkgs/nixos/doc/manual/development/what-happens-during-a-system-switch.chapter.md b/nixpkgs/nixos/doc/manual/development/what-happens-during-a-system-switch.chapter.md
index 5d17a9c98514..28c06f999dac 100644
--- a/nixpkgs/nixos/doc/manual/development/what-happens-during-a-system-switch.chapter.md
+++ b/nixpkgs/nixos/doc/manual/development/what-happens-during-a-system-switch.chapter.md
@@ -56,4 +56,5 @@ explained in the next sections.
 unit-handling.section.md
 activation-script.section.md
 non-switchable-systems.section.md
+etc-overlay.section.md
 ```
diff --git a/nixpkgs/nixos/doc/manual/development/writing-documentation.chapter.md b/nixpkgs/nixos/doc/manual/development/writing-documentation.chapter.md
index 3d9bd318cf33..2e9dffd22ba8 100644
--- a/nixpkgs/nixos/doc/manual/development/writing-documentation.chapter.md
+++ b/nixpkgs/nixos/doc/manual/development/writing-documentation.chapter.md
@@ -7,7 +7,7 @@ worthy contribution to the project.
 
 ## Building the Manual {#sec-writing-docs-building-the-manual}
 
-The DocBook sources of the [](#book-nixos-manual) are in the
+The sources of the [](#book-nixos-manual) are in the
 [`nixos/doc/manual`](https://github.com/NixOS/nixpkgs/tree/master/nixos/doc/manual)
 subdirectory of the Nixpkgs repository.
 
@@ -29,65 +29,3 @@ nix-build nixos/release.nix -A manual.x86_64-linux
 When this command successfully finishes, it will tell you where the
 manual got generated. The HTML will be accessible through the `result`
 symlink at `./result/share/doc/nixos/index.html`.
-
-## Editing DocBook XML {#sec-writing-docs-editing-docbook-xml}
-
-For general information on how to write in DocBook, see [DocBook 5: The
-Definitive Guide](https://tdg.docbook.org/tdg/5.1/).
-
-Emacs nXML Mode is very helpful for editing DocBook XML because it
-validates the document as you write, and precisely locates errors. To
-use it, see [](#sec-emacs-docbook-xml).
-
-[Pandoc](https://pandoc.org/) can generate DocBook XML from a multitude of
-formats, which makes a good starting point. Here is an example of Pandoc
-invocation to convert GitHub-Flavoured MarkDown to DocBook 5 XML:
-
-```ShellSession
-pandoc -f markdown_github -t docbook5 docs.md -o my-section.md
-```
-
-Pandoc can also quickly convert a single `section.xml` to HTML, which is
-helpful when drafting.
-
-Sometimes writing valid DocBook is too difficult. In this case,
-submit your documentation updates in a [GitHub
-Issue](https://github.com/NixOS/nixpkgs/issues/new) and someone will
-handle the conversion to XML for you.
-
-## Creating a Topic {#sec-writing-docs-creating-a-topic}
-
-You can use an existing topic as a basis for the new topic or create a
-topic from scratch.
-
-Keep the following guidelines in mind when you create and add a topic:
-
--   The NixOS [`book`](https://tdg.docbook.org/tdg/5.0/book.html)
-    element is in `nixos/doc/manual/manual.xml`. It includes several
-    [`parts`](https://tdg.docbook.org/tdg/5.0/book.html) which are in
-    subdirectories.
-
--   Store the topic file in the same directory as the `part` to which it
-    belongs. If your topic is about configuring a NixOS module, then the
-    XML file can be stored alongside the module definition `nix` file.
-
--   If you include multiple words in the file name, separate the words
-    with a dash. For example: `ipv6-config.xml`.
-
--   Make sure that the `xml:id` value is unique. You can use abbreviations
-    if the ID is too long. For example: `nixos-config`.
-
--   Determine whether your topic is a chapter or a section. If you are
-    unsure, open an existing topic file and check whether the main
-    element is chapter or section.
-
-## Adding a Topic to the Book {#sec-writing-docs-adding-a-topic}
-
-Open the parent CommonMark file and add a line to the list of
-chapters with the file name of the topic that you created. If you
-created a `section`, you add the file to the `chapter` file. If you created
-a `chapter`, you add the file to the `part` file.
-
-If the topic is about configuring a NixOS module, it can be
-automatically included in the manual by using the `meta.doc` attribute.
-See [](#sec-meta-attributes) for an explanation.
diff --git a/nixpkgs/nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md b/nixpkgs/nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md
index 6d0675f21a03..10bee156d113 100644
--- a/nixpkgs/nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md
+++ b/nixpkgs/nixos/doc/manual/installation/building-images-via-systemd-repart.chapter.md
@@ -75,9 +75,10 @@ image with a new one or by updating partitions via an A/B scheme. See the
 [Chrome OS update process][chrome-os-update] for an example of how to achieve
 this. The appliance image built in the following example does not contain a
 `configuration.nix` and thus you will not be able to call `nixos-rebuild` from
-this system.
+this system. Furthermore, it uses a [Unified Kernel Image][unified-kernel-image].
 
 [chrome-os-update]: https://chromium.googlesource.com/aosp/platform/system/update_engine/+/HEAD/README.md
+[unified-kernel-image]: https://uapi-group.org/specifications/specs/unified_kernel_image/
 
 ```nix
 let
@@ -101,18 +102,8 @@ in
             "/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source =
               "${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
 
-            "/loader/entries/nixos.conf".source = pkgs.writeText "nixos.conf" ''
-              title NixOS
-              linux /EFI/nixos/kernel.efi
-              initrd /EFI/nixos/initrd.efi
-              options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}
-            '';
-
-            "/EFI/nixos/kernel.efi".source =
-              "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
-
-            "/EFI/nixos/initrd.efi".source =
-              "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
+            "/EFI/Linux/${config.system.boot.loader.ukiFile}".source =
+              "${config.system.build.uki}/${config.system.boot.loader.ukiFile}";
           };
           repartConfig = {
             Type = "esp";
diff --git a/nixpkgs/nixos/doc/manual/release-notes/rl-2405.section.md b/nixpkgs/nixos/doc/manual/release-notes/rl-2405.section.md
index 9e8ef49783ca..f6a77036674e 100644
--- a/nixpkgs/nixos/doc/manual/release-notes/rl-2405.section.md
+++ b/nixpkgs/nixos/doc/manual/release-notes/rl-2405.section.md
@@ -8,9 +8,13 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
 
+- `cryptsetup` has been upgraded from 2.6.1 to 2.7.0. Cryptsetup is a critical component enabling LUKS-based (but not only) full disk encryption.
+  Take the time to review [the release notes](https://gitlab.com/cryptsetup/cryptsetup/-/raw/v2.7.0/docs/v2.7.0-ReleaseNotes).
+  One of the highlight is that it is now possible to use hardware OPAL-based encryption of your disk with `cryptsetup`, it has a lot of caveats, see the above notes for the full details.
+
 - `screen`'s module has been cleaned, and will now require you to set `programs.screen.enable` in order to populate `screenrc` and add the program to the environment.
 
-- `linuxPackages_testing_bcachefs` is now fully deprecated by `linuxPackages_testing`, and is therefore no longer available.
+- `linuxPackages_testing_bcachefs` is now fully deprecated by `linuxPackages_latest`, and is therefore no longer available.
 
 - NixOS now installs a stub ELF loader that prints an informative error message when users attempt to run binaries not made for NixOS.
    - This can be disabled through the `environment.stub-ld.enable` option.
@@ -18,31 +22,65 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - Julia environments can now be built with arbitrary packages from the ecosystem using the `.withPackages` function. For example: `julia.withPackages ["Plots"]`.
 
+- A new option `systemd.sysusers.enable` was added. If enabled, users and
+  groups are created with systemd-sysusers instead of with a custom perl script.
+
+- A new option `system.etc.overlay.enable` was added. If enabled, `/etc` is
+  mounted via an overlayfs instead of being created by a custom perl script.
+
+- It is now possible to have a completely perlless system (i.e. a system
+  without perl). Previously, the NixOS activation depended on two perl scripts
+  which can now be replaced via an opt-in mechanism. To make your system
+  perlless, you can use the new perlless profile:
+  ```
+  { modulesPath, ... }: {
+    imports = [ "${modulesPath}/profiles/perlless.nix" ];
+  }
+  ```
+
 ## New Services {#sec-release-24.05-new-services}
 
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
 
+- [Handheld Daemon](https://github.com/hhd-dev/hhd), support for gaming handhelds like the Legion Go, ROG Ally, and GPD Win. Available as [services.handheld-daemon](#opt-services.handheld-daemon.enable).
+
 - [Guix](https://guix.gnu.org), a functional package manager inspired by Nix. Available as [services.guix](#opt-services.guix.enable).
 
+- [pyLoad](https://pyload.net/), a FOSS download manager written in Python. Available as [services.pyload](#opt-services.pyload.enable)
+
 - [maubot](https://github.com/maubot/maubot), a plugin-based Matrix bot framework. Available as [services.maubot](#opt-services.maubot.enable).
 
 - systemd's gateway, upload, and remote services, which provides ways of sending journals across the network. Enable using [services.journald.gateway](#opt-services.journald.gateway.enable), [services.journald.upload](#opt-services.journald.upload.enable), and [services.journald.remote](#opt-services.journald.remote.enable).
 
 - [GNS3](https://www.gns3.com/), a network software emulator. Available as [services.gns3-server](#opt-services.gns3-server.enable).
 
+- [pretalx](https://github.com/pretalx/pretalx), a conference planning tool. Available as [services.pretalx](#opt-services.pretalx.enable).
+
 - [rspamd-trainer](https://gitlab.com/onlime/rspamd-trainer), script triggered by a helper which reads mails from a specific mail inbox and feeds them into rspamd for spam/ham training.
 
 - [ollama](https://ollama.ai), server for running large language models locally.
 
+- [hebbot](https://github.com/haecker-felix/hebbot), a Matrix bot to generate "This Week in X" like blog posts. Available as [services.hebbot](#opt-services.hebbot.enable).
+
 - [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable).
 The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the anki-sync-server softwares.
 
+- [Suwayomi Server](https://github.com/Suwayomi/Suwayomi-Server), a free and open source manga reader server that runs extensions built for [Tachiyomi](https://tachiyomi.org). Available as [services.suwayomi-server](#opt-services.suwayomi-server.enable).
+
 - [ping_exporter](https://github.com/czerwonk/ping_exporter), a Prometheus exporter for ICMP echo requests. Available as [services.prometheus.exporters.ping](#opt-services.prometheus.exporters.ping.enable).
 
+- [TigerBeetle](https://tigerbeetle.com/), a distributed financial accounting database designed for mission critical safety and performance. Available as [services.tigerbeetle](#opt-services.tigerbeetle.enable).
+
 - [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable).
 
 - [TuxClocker](https://github.com/Lurkki14/tuxclocker), a hardware control and monitoring program. Available as [programs.tuxclocker](#opt-programs.tuxclocker.enable).
 
+- [ALVR](https://github.com/alvr-org/alvr), a VR desktop streamer. Available as [programs.alvr](#opt-programs.alvr.enable)
+
+- [RustDesk](https://rustdesk.com), a full-featured open source remote control alternative for self-hosting and security with minimal configuration. Alternative to TeamViewer.
+
+- [systemd-lock-handler](https://git.sr.ht/~whynothugo/systemd-lock-handler/), a bridge between logind D-Bus events and systemd targets. Available as [services.systemd-lock-handler.enable](#opt-services.systemd-lock-handler.enable).
+
 ## Backward Incompatibilities {#sec-release-24.05-incompatibilities}
 
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
@@ -59,10 +97,23 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - `idris2` was updated to v0.7.0. This version introduces breaking changes. Check out the [changelog](https://github.com/idris-lang/Idris2/blob/v0.7.0/CHANGELOG.md#v070) for details.
 
+- `neo4j` has been updated to 5, you may want to read the [release notes for Neo4j 5](https://neo4j.com/release-notes/database/neo4j-5/)
+
+- `services.neo4j.allowUpgrade` was removed and no longer has any effect. Neo4j 5 supports automatic rolling upgrades.
+
 - `nitter` requires a `guest_accounts.jsonl` to be provided as a path or loaded into the default location at `/var/lib/nitter/guest_accounts.jsonl`. See [Guest Account Branch Deployment](https://github.com/zedeus/nitter/wiki/Guest-Account-Branch-Deployment) for details.
 
+- `services.aria2.rpcSecret` has been replaced with `services.aria2.rpcSecretFile`.
+  This was done so that secrets aren't stored in the world-readable nix store.
+  To migrate, you will have create a file with the same exact string, and change
+  your module options to point to that file. For example, `services.aria2.rpcSecret =
+  "mysecret"` becomes `services.aria2.rpcSecretFile = "/path/to/secret_file"`
+  where the file `secret_file` contains the string `mysecret`.
+
 - Invidious has changed its default database username from `kemal` to `invidious`. Setups involving an externally provisioned database (i.e. `services.invidious.database.createLocally == false`) should adjust their configuration accordingly. The old `kemal` user will not be removed automatically even when the database is provisioned automatically.(https://github.com/NixOS/nixpkgs/pull/265857)
 
+- `inetutils` now has a lower priority to avoid shadowing the commonly used `util-linux`. If one wishes to restore the default priority, simply use `lib.setPrio 5 inetutils` or override with `meta.priority = 5`.
+
 - `paperless`' `services.paperless.extraConfig` setting has been removed and converted to the freeform type and option named `services.paperless.settings`.
 
 - The legacy and long deprecated systemd target `network-interfaces.target` has been removed. Use `network.target` instead.
@@ -77,6 +128,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
   release notes of [v19](https://github.com/systemd/mkosi/releases/tag/v19) and
   [v20](https://github.com/systemd/mkosi/releases/tag/v20) for a list of changes.
 
+- The `woodpecker-*` packages have been updated to v2 which includes [breaking changes](https://woodpecker-ci.org/docs/next/migrations#200).
+
 - `services.nginx` will no longer advertise HTTP/3 availability automatically. This must now be manually added, preferably to each location block.
   Example:
 
@@ -89,6 +142,9 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
     '';
 
   ```
+
+- The package `optparse-bash` is now dropped due to upstream inactivity. Alternatives available in Nixpkgs include [`argc`](https://github.com/sigoden/argc), [`argbash`](https://github.com/matejak/argbash), [`bashly`](https://github.com/DannyBen/bashly) and [`gum`](https://github.com/charmbracelet/gum), to name a few.
+
 - The `kanata` package has been updated to v1.5.0, which includes [breaking changes](https://github.com/jtroo/kanata/releases/tag/v1.5.0).
 
 - The `craftos-pc` package has been updated to v2.8, which includes [breaking changes](https://github.com/MCJack123/craftos2/releases/tag/v2.8).
@@ -109,15 +165,32 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - `services.resolved.fallbackDns` can now be used to disable the upstream fallback servers entirely by setting it to an empty list. To get the previous behaviour of the upstream defaults set it to null, the new default, instead.
 
+- `xxd` has been moved from `vim` default output to its own output to reduce closure size. The canonical way to reference it across all platforms is `unixtools.xxd`.
+
 - `services.avahi.nssmdns` got split into `services.avahi.nssmdns4` and `services.avahi.nssmdns6` which enable the mDNS NSS switch for IPv4 and IPv6 respectively.
   Since most mDNS responders only register IPv4 addresses, most users want to keep the IPv6 support disabled to avoid long timeouts.
 
+- A warning has been added for services that are
+  `after = [ "network-online.target" ]` but do not depend on it (e.g. using
+  `wants`), because the dependency that `multi-user.target` has on
+  `network-online.target` is planned for removal.
+
+- `services.archisteamfarm` no longer uses the abbreviation `asf` for its state directory (`/var/lib/asf`), user and group (both `asf`). Instead the long name `archisteamfarm` is used.
+  Configurations with `system.stateVersion` 23.11 or earlier, default to the old stateDirectory until the 24.11 release and must either set the option explicitly or move the data to the new directory.
+
 - `networking.iproute2.enable` now does not set `environment.etc."iproute2/rt_tables".text`.
 
   Setting `environment.etc."iproute2/{CONFIG_FILE_NAME}".text` will override the whole configuration file instead of appending it to the upstream configuration file.
 
   `CONFIG_FILE_NAME` includes `bpf_pinning`, `ematch_map`, `group`, `nl_protos`, `rt_dsfield`, `rt_protos`, `rt_realms`, `rt_scopes`, and `rt_tables`.
 
+- `netbox` was updated to v3.7. `services.netbox.package` still defaults
+  to v3.6 if `stateVersion` is earlier than 24.05. Refer to upstream's breaking
+  changes [for
+  v3.7.0](https://github.com/netbox-community/netbox/releases/tag/v3.7.0) and
+  upgrade NetBox by changing `services.netbox.package`. Database migrations
+  will be run automatically.
+
 - The executable file names for `firefox-devedition`, `firefox-beta`, `firefox-esr` now matches their package names, which is consistent with the `firefox-*-bin` packages. The desktop entries are also updated so that you can have multiple editions of firefox in your app launcher.
 
 - switch-to-configuration does not directly call systemd-tmpfiles anymore.
@@ -143,6 +216,29 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
   The module now includes an optional config check, that is enabled by default, to make the change obvious before any deployment.
   More information about the configuration syntax change is available in the [upstream repository](https://github.com/prometheus/snmp_exporter/blob/b75fc6b839ee3f3ccbee68bee55f1ae99555084a/auth-split-migration.md).
 
+- [watchdogd](https://troglobit.com/projects/watchdogd/), a system and process supervisor using watchdog timers. Available as [services.watchdogd](#opt-services.watchdogd.enable).
+
+- The `jdt-language-server` package now uses upstream's provided python wrapper instead of our own custom wrapper. This results in the following breaking and notable changes:
+
+  - The main binary for the package is now named `jdtls` instead of `jdt-language-server`, equivalent to what most editors expect the binary to be named.
+
+  - JVM arguments should now be provided with the `--jvm-arg` flag instead of setting `JAVA_OPTS`.
+
+  - The `-data` path is no longer required to run the package, and will be set to point to a folder in `$TMP` if missing.
+
+- `nomad` has been updated - note that HashiCorp recommends updating one minor version at a time. Please check [their upgrade guide](https://developer.hashicorp.com/nomad/docs/upgrade) for information on safely updating clusters and potential breaking changes.
+
+  - `nomad` is now Nomad 1.7.x.
+
+  - `nomad_1_4` has been removed, as it is now unsupported upstream.
+
+- The `livebook` package is now built as a `mix release` instead of an `escript`.
+  This means that configuration now has to be done using [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) instead of command line arguments.
+  This has the further implication that the `livebook` service configuration has changed:
+
+  - The `erlang_node_short_name`, `erlang_node_name`, `port` and `options` configuration parameters are gone, and have been replaced with an `environment` parameter.
+    Use the appropriate [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) inside `environment` to configure the service instead.
+
 ## Other Notable Changes {#sec-release-24.05-notable-changes}
 
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
@@ -154,6 +250,9 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 - `services.postgresql.extraPlugins` changed its type from just a list of packages to also a function that returns such a list.
   For example a config line like ``services.postgresql.extraPlugins = with pkgs.postgresql_11.pkgs; [ postgis ];`` is recommended to be changed to ``services.postgresql.extraPlugins = ps: with ps; [ postgis ];``;
 
+- The Matrix homeserver [Synapse](https://element-hq.github.io/synapse/) module now supports configuring UNIX domain socket [listeners](#opt-services.matrix-synapse.settings.listeners) through the `path` option.
+  The default replication worker on the main instance has been migrated away from TCP sockets to UNIX domain sockets.
+
 - Programs written in [Nim](https://nim-lang.org/) are built with libraries selected by lockfiles.
   The `nimPackages` and `nim2Packages` sets have been removed.
   See https://nixos.org/manual/nixpkgs/unstable#nim for more information.
@@ -163,32 +262,56 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
   After upgrading, follow the instructions on the [upstream release notes](https://github.com/majewsky/portunus/releases/tag/v2.0.0) to upgrade all user accounts to strong password hashes.
   Support for weak password hashes will be removed in NixOS 24.11.
 
+- A stdenv's default set of hardening flags can now be set via its `bintools-wrapper`'s `defaultHardeningFlags` argument. A convenient stdenv adapter, `withDefaultHardeningFlags`, can be used to override an existing stdenv's `defaultHardeningFlags`.
+
 - `libass` now uses the native CoreText backend on Darwin, which may fix subtitle rendering issues with `mpv`, `ffmpeg`, etc.
 
 - [Lilypond](https://lilypond.org/index.html) and [Denemo](https://www.denemo.org) are now compiled with Guile 3.0.
 
-- The following options of the Nextcloud module were moved into [`services.nextcloud.extraOptions`](#opt-services.nextcloud.extraOptions) and renamed to match the name from Nextcloud's `config.php`:
-  - `logLevel` -> [`loglevel`](#opt-services.nextcloud.extraOptions.loglevel),
-  - `logType` -> [`log_type`](#opt-services.nextcloud.extraOptions.log_type),
-  - `defaultPhoneRegion` -> [`default_phone_region`](#opt-services.nextcloud.extraOptions.default_phone_region),
-  - `overwriteProtocol` -> [`overwriteprotocol`](#opt-services.nextcloud.extraOptions.overwriteprotocol),
-  - `skeletonDirectory` -> [`skeletondirectory`](#opt-services.nextcloud.extraOptions.skeletondirectory),
-  - `globalProfiles` -> [`profile.enabled`](#opt-services.nextcloud.extraOptions._profile.enabled_),
-  - `extraTrustedDomains` -> [`trusted_domains`](#opt-services.nextcloud.extraOptions.trusted_domains) and
-  - `trustedProxies` -> [`trusted_proxies`](#opt-services.nextcloud.extraOptions.trusted_proxies).
+- The following options of the Nextcloud module were moved into [`services.nextcloud.settings`](#opt-services.nextcloud.settings) and renamed to match the name from Nextcloud's `config.php`:
+  - `logLevel` -> [`loglevel`](#opt-services.nextcloud.settings.loglevel),
+  - `logType` -> [`log_type`](#opt-services.nextcloud.settings.log_type),
+  - `defaultPhoneRegion` -> [`default_phone_region`](#opt-services.nextcloud.settings.default_phone_region),
+  - `overwriteProtocol` -> [`overwriteprotocol`](#opt-services.nextcloud.settings.overwriteprotocol),
+  - `skeletonDirectory` -> [`skeletondirectory`](#opt-services.nextcloud.settings.skeletondirectory),
+  - `globalProfiles` -> [`profile.enabled`](#opt-services.nextcloud.settings._profile.enabled_),
+  - `extraTrustedDomains` -> [`trusted_domains`](#opt-services.nextcloud.settings.trusted_domains) and
+  - `trustedProxies` -> [`trusted_proxies`](#opt-services.nextcloud.settings.trusted_proxies).
 
 - The option [`services.nextcloud.config.dbport`] of the Nextcloud module was removed to match upstream.
   The port can be specified in [`services.nextcloud.config.dbhost`](#opt-services.nextcloud.config.dbhost).
 
+- A new abstraction to create both read-only as well as writable overlay file
+  systems was added. Available via
+  [fileSystems.overlay](#opt-fileSystems._name_.overlay.lowerdir). See also the
+  [NixOS docs](#sec-overlayfs).
+
+- systemd units can now specify the `Upholds=` and `UpheldBy=` unit dependencies via the aptly
+  named `upholds` and `upheldBy` options. These options get systemd to enforce that the
+  dependencies remain continuosly running for as long as the dependent unit is in a running state.
+
+- `stdenv`: The `--replace` flag in `substitute`, `substituteInPlace`, `substituteAll`, `substituteAllStream`, and `substituteStream` is now deprecated if favor of the new `--replace-fail`, `--replace-warn` and `--replace-quiet`. The deprecated `--replace` equates to `--replace-warn`.
+
+- A new hardening flag, `zerocallusedregs` was made available, corresponding to the gcc/clang option `-fzero-call-used-regs=used-gpr`.
+
+- New options were added to the dnsdist module to enable and configure a DNSCrypt endpoint (see `services.dnsdist.dnscrypt.enable`, etc.).
+  The module can generate the DNSCrypt provider key pair, certificates and also performs their rotation automatically with no downtime.
+
+- With a bump to `sonarr` v4, existing config database files will be upgraded automatically, but note that some old apparently-working configs [might actually be corrupt and fail to upgrade cleanly](https://forums.sonarr.tv/t/sonarr-v4-released/33089).
+
 - The Yama LSM is now enabled by default in the kernel, which prevents ptracing
   non-child processes. This means you will not be able to attach gdb to an
   existing process, but will need to start that process from gdb (so it is a
   child). Or you can set `boot.kernel.sysctl."kernel.yama.ptrace_scope"` to 0.
 
+- The netbird module now allows running multiple tunnels in parallel through [`services.netbird.tunnels`](#opt-services.netbird.tunnels).
+
 - [Nginx virtual hosts](#opt-services.nginx.virtualHosts) using `forceSSL` or
   `globalRedirect` can now have redirect codes other than 301 through
   `redirectCode`.
 
+- `libjxl` 0.9.0 [dropped support for the butteraugli API](https://github.com/libjxl/libjxl/pull/2576). You will no longer be able to set `enableButteraugli` on `libaom`.
+
 - The source of the `mockgen` package has changed to the [go.uber.org/mock](https://github.com/uber-go/mock) fork because [the original repository is no longer maintained](https://github.com/golang/mock#gomock).
 
 - `security.pam.enableSSHAgentAuth` was renamed to `security.pam.sshAgentAuth.enable` and an `authorizedKeysFiles`
@@ -197,17 +320,25 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - [](#opt-boot.kernel.sysctl._net.core.wmem_max_) changed from a string to an integer because of the addition of a custom merge option (taking the highest value defined to avoid conflicts between 2 services trying to set that value), just as [](#opt-boot.kernel.sysctl._net.core.rmem_max_) since 22.11.
 
+- A new top-level package set, `pkgsExtraHardening` is added. This is a set of packages built with stricter hardening flags - those that have not yet received enough testing to be applied universally, those that are more likely to cause build failures or those that have drawbacks to their use (e.g. performance or required hardware features).
+
 - `services.zfs.zed.enableMail` now uses the global `sendmail` wrapper defined by an email module
   (such as msmtp or Postfix). It no longer requires using a special ZFS build with email support.
 
+- `nextcloud-setup.service` no longer changes the group of each file & directory inside `/var/lib/nextcloud/{config,data,store-apps}` if one of these directories has the wrong owner group. This was part of transitioning the group used for `/var/lib/nextcloud`, but isn't necessary anymore.
+
 - The `krb5` module has been rewritten and moved to `security.krb5`, moving all options but `security.krb5.enable` and `security.krb5.package` into `security.krb5.settings`.
 
 - Gitea 1.21 upgrade has several breaking changes, including:
   - Custom themes and other assets that were previously stored in `custom/public/*` now belong in `custom/public/assets/*`
   - New instances of Gitea using MySQL now ignore the `[database].CHARSET` config option and always use the `utf8mb4` charset, existing instances should migrate via the `gitea doctor convert` CLI command.
 
+- The `services.paperless` module no longer uses the previously downloaded NLTK data stored in `/var/cache/paperless/nltk`. This directory can be removed.
+
 - The `hardware.pulseaudio` module now sets permission of pulse user home directory to 755 when running in "systemWide" mode. It fixes [issue 114399](https://github.com/NixOS/nixpkgs/issues/114399).
 
+- The module `services.github-runner` has been removed. To configure a single GitHub Actions Runner refer to `services.github-runners.*`. Note that this will trigger a new runner registration.
+
 - The `btrbk` module now automatically selects and provides required compression
   program depending on the configured `stream_compress` option. Since this
   replaces the need for the `extraPackages` option, this option will be
@@ -215,5 +346,9 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - The `mpich` package expression now requires `withPm` to be a list, e.g. `"hydra:gforker"` becomes `[ "hydra" "gforker" ]`.
 
+- YouTrack is bumped to 2023.3. The update is not performed automatically, it requires manual interaction. See the YouTrack section in the manual for details.
+
 - QtMultimedia has changed its default backend to `QT_MEDIA_BACKEND=ffmpeg` (previously `gstreamer` on Linux or `darwin` on MacOS).
   The previous native backends remain available but are now minimally maintained. Refer to [upstream documentation](https://doc.qt.io/qt-6/qtmultimedia-index.html#ffmpeg-as-the-default-backend) for further details about each platform.
+
+- The oil shell is now using the c++ version by default. The python based build is still available as `oil-python`
diff --git a/nixpkgs/nixos/lib/eval-config.nix b/nixpkgs/nixos/lib/eval-config.nix
index da099f86aa2c..8bab3752073f 100644
--- a/nixpkgs/nixos/lib/eval-config.nix
+++ b/nixpkgs/nixos/lib/eval-config.nix
@@ -110,6 +110,7 @@ let
   withExtraAttrs = configuration: configuration // {
     inherit extraArgs;
     inherit (configuration._module.args) pkgs;
+    inherit lib;
     extendModules = args: withExtraAttrs (configuration.extendModules args);
   };
 in
diff --git a/nixpkgs/nixos/lib/systemd-lib.nix b/nixpkgs/nixos/lib/systemd-lib.nix
index 347ee7303936..c9cca619ed70 100644
--- a/nixpkgs/nixos/lib/systemd-lib.nix
+++ b/nixpkgs/nixos/lib/systemd-lib.nix
@@ -242,7 +242,7 @@ in rec {
             ln -sfn '${name}' $out/'${name2}'
           '') (unit.aliases or [])) units)}
 
-      # Create .wants and .requires symlinks from the wantedBy and
+      # Create .wants, .upholds and .requires symlinks from the wantedBy, upheldBy and
       # requiredBy options.
       ${concatStrings (mapAttrsToList (name: unit:
           concatMapStrings (name2: ''
@@ -252,6 +252,12 @@ in rec {
 
       ${concatStrings (mapAttrsToList (name: unit:
           concatMapStrings (name2: ''
+            mkdir -p $out/'${name2}.upholds'
+            ln -sfn '../${name}' $out/'${name2}.upholds'/
+          '') (unit.upheldBy or [])) units)}
+
+      ${concatStrings (mapAttrsToList (name: unit:
+          concatMapStrings (name2: ''
             mkdir -p $out/'${name2}.requires'
             ln -sfn '../${name}' $out/'${name2}.requires'/
           '') (unit.requiredBy or [])) units)}
@@ -289,6 +295,8 @@ in rec {
           { Requires = toString config.requires; }
         // optionalAttrs (config.wants != [])
           { Wants = toString config.wants; }
+        // optionalAttrs (config.upholds != [])
+          { Upholds = toString config.upholds; }
         // optionalAttrs (config.after != [])
           { After = toString config.after; }
         // optionalAttrs (config.before != [])
diff --git a/nixpkgs/nixos/lib/systemd-unit-options.nix b/nixpkgs/nixos/lib/systemd-unit-options.nix
index 9c69bda471bb..df05d165d9e8 100644
--- a/nixpkgs/nixos/lib/systemd-unit-options.nix
+++ b/nixpkgs/nixos/lib/systemd-unit-options.nix
@@ -74,6 +74,15 @@ in rec {
       '';
     };
 
+    upheldBy = mkOption {
+      default = [];
+      type = types.listOf unitNameType;
+      description = lib.mdDoc ''
+        Keep this unit running as long as the listed units are running. This is a continuously
+        enforced version of wantedBy.
+      '';
+    };
+
     wantedBy = mkOption {
       default = [];
       type = types.listOf unitNameType;
@@ -147,6 +156,14 @@ in rec {
         '';
       };
 
+      upholds = mkOption {
+        default = [];
+        type = types.listOf unitNameType;
+        description = lib.mdDoc ''
+          Keeps the specified running while this unit is running. A continuous version of `wants`.
+        '';
+      };
+
       after = mkOption {
         default = [];
         type = types.listOf unitNameType;
diff --git a/nixpkgs/nixos/lib/test-driver/test_driver/machine.py b/nixpkgs/nixos/lib/test-driver/test_driver/machine.py
index da60b669fa27..93411a4a348e 100644
--- a/nixpkgs/nixos/lib/test-driver/test_driver/machine.py
+++ b/nixpkgs/nixos/lib/test-driver/test_driver/machine.py
@@ -768,6 +768,32 @@ class Machine:
             self.booted = False
             self.connected = False
 
+    def wait_for_qmp_event(
+        self, event_filter: Callable[[dict[str, Any]], bool], timeout: int = 60 * 10
+    ) -> dict[str, Any]:
+        """
+        Wait for a QMP event which you can filter with the `event_filter` function.
+        The function takes as an input a dictionary of the event and if it returns True, we return that event,
+        if it does not, we wait for the next event and retry.
+
+        It will skip all events received in the meantime, if you want to keep them,
+        you have to do the bookkeeping yourself and store them somewhere.
+
+        By default, it will wait up to 10 minutes, `timeout` is in seconds.
+        """
+        if self.qmp_client is None:
+            raise RuntimeError("QMP API is not ready yet, is the VM ready?")
+
+        start = time.time()
+        while True:
+            evt = self.qmp_client.wait_for_event(timeout=timeout)
+            if event_filter(evt):
+                return evt
+
+            elapsed = time.time() - start
+            if elapsed >= timeout:
+                raise TimeoutError
+
     def get_tty_text(self, tty: str) -> str:
         status, output = self.execute(
             f"fold -w$(stty -F /dev/tty{tty} size | "
diff --git a/nixpkgs/nixos/lib/utils.nix b/nixpkgs/nixos/lib/utils.nix
index e618cf2f861a..49ba2e5c8386 100644
--- a/nixpkgs/nixos/lib/utils.nix
+++ b/nixpkgs/nixos/lib/utils.nix
@@ -109,6 +109,7 @@ rec {
       recurse = prefix: item:
         if item ? ${attr} then
           nameValuePair prefix item.${attr}
+        else if isDerivation item then []
         else if isAttrs item then
           map (name:
             let
diff --git a/nixpkgs/nixos/maintainers/scripts/ec2/README.md b/nixpkgs/nixos/maintainers/scripts/ec2/README.md
new file mode 100644
index 000000000000..1328109d464a
--- /dev/null
+++ b/nixpkgs/nixos/maintainers/scripts/ec2/README.md
@@ -0,0 +1,7 @@
+# Amazon images
+
+* The `create-amis.sh` script will be replaced by https://github.com/NixOS/amis which will regularly upload AMIs per NixOS channel bump.
+
+* @arianvp is planning to drop zfs support
+* @arianvp is planning to rewrite the image builder to use the repart-based image builder.
+
diff --git a/nixpkgs/nixos/maintainers/scripts/ec2/amazon-image.nix b/nixpkgs/nixos/maintainers/scripts/ec2/amazon-image.nix
index d12339bca1f8..055d44ba6576 100644
--- a/nixpkgs/nixos/maintainers/scripts/ec2/amazon-image.nix
+++ b/nixpkgs/nixos/maintainers/scripts/ec2/amazon-image.nix
@@ -157,4 +157,6 @@ in {
       '';
     };
   in if config.ec2.zfs.enable then zfsBuilder else extBuilder;
+
+  meta.maintainers = with maintainers; [ arianvp ];
 }
diff --git a/nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image-inner.nix b/nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image-inner.nix
index c1c50b32ff5b..2d1761401fcd 100644
--- a/nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image-inner.nix
+++ b/nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image-inner.nix
@@ -13,8 +13,22 @@
       ./lxd.nix
     ];
 
-  networking.useDHCP = false;
-  networking.interfaces.eth0.useDHCP = true;
+  networking = {
+    dhcdpcd.enable = false;
+    useDHCP = false;
+  };
+
+  systemd.network = {
+    enable = true;
+    networks."50-eth0" = {
+      matchConfig.Name = "eth0";
+      networkConfig = {
+        DHCP = "ipv4";
+        IPv6AcceptRA = true;
+      };
+      linkConfig.RequiredForOnline = "routable";
+    };
+  };
 
   system.stateVersion = "@stateVersion@"; # Did you read the comment?
 }
diff --git a/nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image.nix b/nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image.nix
index 0d96eea0e2d2..a58579914465 100644
--- a/nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image.nix
+++ b/nixpkgs/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image.nix
@@ -26,6 +26,20 @@
   '';
 
   # Network
-  networking.useDHCP = false;
-  networking.interfaces.enp5s0.useDHCP = true;
+  networking = {
+    dhcdpcd.enable = false;
+    useDHCP = false;
+  };
+
+  systemd.network = {
+    enable = true;
+    networks."50-enp5s0" = {
+      matchConfig.Name = "enp5s0";
+      networkConfig = {
+        DHCP = "ipv4";
+        IPv6AcceptRA = true;
+      };
+      linkConfig.RequiredForOnline = "routable";
+    };
+  };
 }
diff --git a/nixpkgs/nixos/modules/config/no-x-libs.nix b/nixpkgs/nixos/modules/config/no-x-libs.nix
index 4727e5b85ef2..2f763290e32d 100644
--- a/nixpkgs/nixos/modules/config/no-x-libs.nix
+++ b/nixpkgs/nixos/modules/config/no-x-libs.nix
@@ -30,6 +30,7 @@ with lib;
       beam = super.beam_nox;
       cairo = super.cairo.override { x11Support = false; };
       dbus = super.dbus.override { x11Support = false; };
+      fastfetch = super.fastfetch.override { vulkanSupport = false; waylandSupport = false; x11Support = false; };
       ffmpeg_4 = super.ffmpeg_4.override { ffmpegVariant = "headless"; };
       ffmpeg_5 = super.ffmpeg_5.override { ffmpegVariant = "headless"; };
       # dep of graphviz, libXpm is optional for Xpm support
@@ -37,6 +38,7 @@ with lib;
       ghostscript = super.ghostscript.override { cupsSupport = false; x11Support = false; };
       gjs = super.gjs.overrideAttrs { doCheck = false; installTests = false; }; # avoid test dependency on gtk3
       gobject-introspection = super.gobject-introspection.override { x11Support = false; };
+      gpg-tui = super.gpg-tui.override { x11Support = false; };
       gpsd = super.gpsd.override { guiSupport = false; };
       graphviz = super.graphviz-nox;
       gst_all_1 = super.gst_all_1 // {
diff --git a/nixpkgs/nixos/modules/config/shells-environment.nix b/nixpkgs/nixos/modules/config/shells-environment.nix
index bc6583442edf..a8476bd2aaed 100644
--- a/nixpkgs/nixos/modules/config/shells-environment.nix
+++ b/nixpkgs/nixos/modules/config/shells-environment.nix
@@ -214,7 +214,8 @@ in
       ''
         # Create the required /bin/sh symlink; otherwise lots of things
         # (notably the system() function) won't work.
-        mkdir -m 0755 -p /bin
+        mkdir -p /bin
+        chmod 0755 /bin
         ln -sfn "${cfg.binsh}" /bin/.sh.tmp
         mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh
       '';
diff --git a/nixpkgs/nixos/modules/config/users-groups.nix b/nixpkgs/nixos/modules/config/users-groups.nix
index 2aed620eb154..967ad0846d75 100644
--- a/nixpkgs/nixos/modules/config/users-groups.nix
+++ b/nixpkgs/nixos/modules/config/users-groups.nix
@@ -685,7 +685,7 @@ in {
       shadow.gid = ids.gids.shadow;
     };
 
-    system.activationScripts.users = {
+    system.activationScripts.users = if !config.systemd.sysusers.enable then {
       supportsDryActivation = true;
       text = ''
         install -m 0700 -d /root
@@ -694,7 +694,7 @@ in {
         ${pkgs.perl.withPackages (p: [ p.FileSlurp p.JSON ])}/bin/perl \
         -w ${./update-users-groups.pl} ${spec}
       '';
-    };
+    } else ""; # keep around for backwards compatibility
 
     system.activationScripts.update-lingering = let
       lingerDir = "/var/lib/systemd/linger";
@@ -711,7 +711,9 @@ in {
     '';
 
     # Warn about user accounts with deprecated password hashing schemes
-    system.activationScripts.hashes = {
+    # This does not work when the users and groups are created by
+    # systemd-sysusers because the users are created too late then.
+    system.activationScripts.hashes = if !config.systemd.sysusers.enable then {
       deps = [ "users" ];
       text = ''
         users=()
@@ -729,7 +731,7 @@ in {
           printf ' - %s\n' "''${users[@]}"
         fi
       '';
-    };
+    } else ""; # keep around for backwards compatibility
 
     # for backwards compatibility
     system.activationScripts.groups = stringAfter [ "users" ] "";
diff --git a/nixpkgs/nixos/modules/hardware/corectrl.nix b/nixpkgs/nixos/modules/hardware/corectrl.nix
index 8ef61a158d5c..b1d3f2f0ce7e 100644
--- a/nixpkgs/nixos/modules/hardware/corectrl.nix
+++ b/nixpkgs/nixos/modules/hardware/corectrl.nix
@@ -12,6 +12,10 @@ in
       Add your user to the corectrl group to run corectrl without needing to enter your password
     '');
 
+    package = mkPackageOption pkgs "corectrl" {
+      extraDescription = "Useful for overriding the configuration options used for the package.";
+    };
+
     gpuOverclock = {
       enable = mkEnableOption (lib.mdDoc ''
         GPU overclocking
@@ -32,9 +36,9 @@ in
 
   config = mkIf cfg.enable (lib.mkMerge [
     {
-      environment.systemPackages = [ pkgs.corectrl ];
+      environment.systemPackages = [ cfg.package ];
 
-      services.dbus.packages = [ pkgs.corectrl ];
+      services.dbus.packages = [ cfg.package ];
 
       users.groups.corectrl = { };
 
diff --git a/nixpkgs/nixos/modules/image/repart-image.nix b/nixpkgs/nixos/modules/image/repart-image.nix
index b4a1dfe51ff3..7ac47ee32ff4 100644
--- a/nixpkgs/nixos/modules/image/repart-image.nix
+++ b/nixpkgs/nixos/modules/image/repart-image.nix
@@ -10,6 +10,8 @@
 , systemd
 , fakeroot
 , util-linux
+
+  # filesystem tools
 , dosfstools
 , mtools
 , e2fsprogs
@@ -18,13 +20,19 @@
 , btrfs-progs
 , xfsprogs
 
+  # compression tools
+, zstd
+, xz
+
   # arguments
-, name
+, imageFileBasename
+, compression
 , fileSystems
 , partitions
 , split
 , seed
 , definitionsDirectory
+, sectorSize
 }:
 
 let
@@ -52,14 +60,25 @@ let
   };
 
   fileSystemTools = builtins.concatMap (f: fileSystemToolMapping."${f}") fileSystems;
+
+  compressionPkg = {
+    "zstd" = zstd;
+    "xz" = xz;
+  }."${compression.algorithm}";
+
+  compressionCommand = {
+    "zstd" = "zstd --no-progress --threads=0 -${toString compression.level}";
+    "xz" = "xz --keep --verbose --threads=0 -${toString compression.level}";
+  }."${compression.algorithm}";
 in
 
-runCommand name
+runCommand imageFileBasename
 {
   nativeBuildInputs = [
     systemd
     fakeroot
     util-linux
+    compressionPkg
   ] ++ fileSystemTools;
 } ''
   amendedRepartDefinitions=$(${amendRepartDefinitions} ${partitions} ${definitionsDirectory})
@@ -67,6 +86,7 @@ runCommand name
   mkdir -p $out
   cd $out
 
+  echo "Building image with systemd-repart..."
   unshare --map-root-user fakeroot systemd-repart \
     --dry-run=no \
     --empty=create \
@@ -75,6 +95,18 @@ runCommand name
     --definitions="$amendedRepartDefinitions" \
     --split="${lib.boolToString split}" \
     --json=pretty \
-    image.raw \
+    ${lib.optionalString (sectorSize != null) "--sector-size=${toString sectorSize}"} \
+    ${imageFileBasename}.raw \
     | tee repart-output.json
+
+  # Compression is implemented in the same derivation as opposed to in a
+  # separate derivation to allow users to save disk space. Disk images are
+  # already very space intensive so we want to allow users to mitigate this.
+  if ${lib.boolToString compression.enable}; then
+    for f in ${imageFileBasename}*; do
+      echo "Compressing $f with ${compression.algorithm}..."
+      # Keep the original file when compressing and only delete it afterwards
+      ${compressionCommand} $f && rm $f
+    done
+  fi
 ''
diff --git a/nixpkgs/nixos/modules/image/repart.nix b/nixpkgs/nixos/modules/image/repart.nix
index da4f45d9a639..6a933f0d83cc 100644
--- a/nixpkgs/nixos/modules/image/repart.nix
+++ b/nixpkgs/nixos/modules/image/repart.nix
@@ -66,7 +66,53 @@ in
 
     name = lib.mkOption {
       type = lib.types.str;
-      description = lib.mdDoc "The name of the image.";
+      description = lib.mdDoc ''
+        Name of the image.
+
+        If this option is unset but config.system.image.id is set,
+        config.system.image.id is used as the default value.
+      '';
+    };
+
+    version = lib.mkOption {
+      type = lib.types.nullOr lib.types.str;
+      default = config.system.image.version;
+      defaultText = lib.literalExpression "config.system.image.version";
+      description = lib.mdDoc "Version of the image";
+    };
+
+    imageFileBasename = lib.mkOption {
+      type = lib.types.str;
+      readOnly = true;
+      description = lib.mdDoc ''
+        Basename of the image filename without any extension (e.g. `image_1`).
+      '';
+    };
+
+    imageFile = lib.mkOption {
+      type = lib.types.str;
+      readOnly = true;
+      description = lib.mdDoc ''
+        Filename of the image including all extensions (e.g `image_1.raw` or
+        `image_1.raw.zst`).
+      '';
+    };
+
+    compression = {
+      enable = lib.mkEnableOption (lib.mdDoc "Image compression");
+
+      algorithm = lib.mkOption {
+        type = lib.types.enum [ "zstd" "xz" ];
+        default = "zstd";
+        description = lib.mdDoc "Compression algorithm";
+      };
+
+      level = lib.mkOption {
+        type = lib.types.int;
+        description = lib.mdDoc ''
+          Compression level. The available range depends on the used algorithm.
+        '';
+      };
     };
 
     seed = lib.mkOption {
@@ -89,6 +135,16 @@ in
       '';
     };
 
+    sectorSize = lib.mkOption {
+      type = with lib.types; nullOr int;
+      default = 512;
+      example = lib.literalExpression "4096";
+      description = lib.mdDoc ''
+        The sector size of the disk image produced by systemd-repart. This
+        value must be a power of 2 between 512 and 4096.
+      '';
+    };
+
     package = lib.mkPackageOption pkgs "systemd-repart" {
       # We use buildPackages so that repart images are built with the build
       # platform's systemd, allowing for cross-compiled systems to work.
@@ -131,6 +187,32 @@ in
 
   config = {
 
+    image.repart =
+      let
+        version = config.image.repart.version;
+        versionInfix = if version != null then "_${version}" else "";
+        compressionSuffix = lib.optionalString cfg.compression.enable
+          {
+            "zstd" = ".zst";
+            "xz" = ".xz";
+          }."${cfg.compression.algorithm}";
+      in
+      {
+        name = lib.mkIf (config.system.image.id != null) (lib.mkOptionDefault config.system.image.id);
+        imageFileBasename = cfg.name + versionInfix;
+        imageFile = cfg.imageFileBasename + ".raw" + compressionSuffix;
+
+        compression = {
+          # Generally default to slightly faster than default compression
+          # levels under the assumption that most of the building will be done
+          # for development and release builds will be customized.
+          level = lib.mkOptionDefault {
+            "zstd" = 3;
+            "xz" = 3;
+          }."${cfg.compression.algorithm}";
+        };
+      };
+
     system.build.image =
       let
         fileSystems = lib.filter
@@ -160,7 +242,7 @@ in
       in
       pkgs.callPackage ./repart-image.nix {
         systemd = cfg.package;
-        inherit (cfg) name split seed;
+        inherit (cfg) imageFileBasename compression split seed sectorSize;
         inherit fileSystems definitionsDirectory partitions;
       };
 
diff --git a/nixpkgs/nixos/modules/misc/ids.nix b/nixpkgs/nixos/modules/misc/ids.nix
index 5af7284ac71a..cfa98c838af5 100644
--- a/nixpkgs/nixos/modules/misc/ids.nix
+++ b/nixpkgs/nixos/modules/misc/ids.nix
@@ -313,7 +313,7 @@ in
       kanboard = 281;
       # pykms = 282; # DynamicUser = true
       kodi = 283;
-      restya-board = 284;
+      # restya-board = 284; # removed 2024-01-22
       mighttpd2 = 285;
       hass = 286;
       #monero = 287; # dynamically allocated as of 2021-05-08
@@ -623,7 +623,7 @@ in
       kanboard = 281;
       # pykms = 282; # DynamicUser = true
       kodi = 283;
-      restya-board = 284;
+      # restya-board = 284; # removed 2024-01-22
       mighttpd2 = 285;
       hass = 286;
       # monero = 287; # dynamically allocated as of 2021-05-08
diff --git a/nixpkgs/nixos/modules/misc/version.nix b/nixpkgs/nixos/modules/misc/version.nix
index 45dbf45b3ae7..79b95ac654d5 100644
--- a/nixpkgs/nixos/modules/misc/version.nix
+++ b/nixpkgs/nixos/modules/misc/version.nix
@@ -5,32 +5,39 @@ let
   opt = options.system.nixos;
 
   inherit (lib)
-    concatStringsSep mapAttrsToList toLower
+    concatStringsSep mapAttrsToList toLower optionalString
     literalExpression mkRenamedOptionModule mkDefault mkOption trivial types;
 
   needsEscaping = s: null != builtins.match "[a-zA-Z0-9]+" s;
   escapeIfNecessary = s: if needsEscaping s then s else ''"${lib.escape [ "\$" "\"" "\\" "\`" ] s}"'';
   attrsToText = attrs:
-    concatStringsSep "\n" (
-      mapAttrsToList (n: v: ''${n}=${escapeIfNecessary (toString v)}'') attrs
-    ) + "\n";
-
-  osReleaseContents = {
-    NAME = "${cfg.distroName}";
-    ID = "${cfg.distroId}";
-    VERSION = "${cfg.release} (${cfg.codeName})";
-    VERSION_CODENAME = toLower cfg.codeName;
-    VERSION_ID = cfg.release;
-    BUILD_ID = cfg.version;
-    PRETTY_NAME = "${cfg.distroName} ${cfg.release} (${cfg.codeName})";
-    LOGO = "nix-snowflake";
-    HOME_URL = lib.optionalString (cfg.distroId == "nixos") "https://nixos.org/";
-    DOCUMENTATION_URL = lib.optionalString (cfg.distroId == "nixos") "https://nixos.org/learn.html";
-    SUPPORT_URL = lib.optionalString (cfg.distroId == "nixos") "https://nixos.org/community.html";
-    BUG_REPORT_URL = lib.optionalString (cfg.distroId == "nixos") "https://github.com/NixOS/nixpkgs/issues";
-  } // lib.optionalAttrs (cfg.variant_id != null) {
-    VARIANT_ID = cfg.variant_id;
-  };
+    concatStringsSep "\n"
+      (mapAttrsToList (n: v: ''${n}=${escapeIfNecessary (toString v)}'') attrs)
+    + "\n";
+
+  osReleaseContents =
+    let
+      isNixos = cfg.distroId == "nixos";
+    in
+    {
+      NAME = "${cfg.distroName}";
+      ID = "${cfg.distroId}";
+      VERSION = "${cfg.release} (${cfg.codeName})";
+      VERSION_CODENAME = toLower cfg.codeName;
+      VERSION_ID = cfg.release;
+      BUILD_ID = cfg.version;
+      PRETTY_NAME = "${cfg.distroName} ${cfg.release} (${cfg.codeName})";
+      LOGO = "nix-snowflake";
+      HOME_URL = optionalString isNixos "https://nixos.org/";
+      DOCUMENTATION_URL = optionalString isNixos "https://nixos.org/learn.html";
+      SUPPORT_URL = optionalString isNixos "https://nixos.org/community.html";
+      BUG_REPORT_URL = optionalString isNixos "https://github.com/NixOS/nixpkgs/issues";
+      ANSI_COLOR = optionalString isNixos "1;34";
+      IMAGE_ID = optionalString (config.system.image.id != null) config.system.image.id;
+      IMAGE_VERSION = optionalString (config.system.image.version != null) config.system.image.version;
+    } // lib.optionalAttrs (cfg.variant_id != null) {
+      VARIANT_ID = cfg.variant_id;
+    };
 
   initrdReleaseContents = (removeAttrs osReleaseContents [ "BUILD_ID" ]) // {
     PRETTY_NAME = "${osReleaseContents.PRETTY_NAME} (Initrd)";
@@ -54,60 +61,93 @@ in
   };
 
   options.system = {
+    nixos = {
+      version = mkOption {
+        internal = true;
+        type = types.str;
+        description = lib.mdDoc "The full NixOS version (e.g. `16.03.1160.f2d4ee1`).";
+      };
 
-    nixos.version = mkOption {
-      internal = true;
-      type = types.str;
-      description = lib.mdDoc "The full NixOS version (e.g. `16.03.1160.f2d4ee1`).";
-    };
+      release = mkOption {
+        readOnly = true;
+        type = types.str;
+        default = trivial.release;
+        description = lib.mdDoc "The NixOS release (e.g. `16.03`).";
+      };
 
-    nixos.release = mkOption {
-      readOnly = true;
-      type = types.str;
-      default = trivial.release;
-      description = lib.mdDoc "The NixOS release (e.g. `16.03`).";
-    };
+      versionSuffix = mkOption {
+        internal = true;
+        type = types.str;
+        default = trivial.versionSuffix;
+        description = lib.mdDoc "The NixOS version suffix (e.g. `1160.f2d4ee1`).";
+      };
 
-    nixos.versionSuffix = mkOption {
-      internal = true;
-      type = types.str;
-      default = trivial.versionSuffix;
-      description = lib.mdDoc "The NixOS version suffix (e.g. `1160.f2d4ee1`).";
-    };
+      revision = mkOption {
+        internal = true;
+        type = types.nullOr types.str;
+        default = trivial.revisionWithDefault null;
+        description = lib.mdDoc "The Git revision from which this NixOS configuration was built.";
+      };
 
-    nixos.revision = mkOption {
-      internal = true;
-      type = types.nullOr types.str;
-      default = trivial.revisionWithDefault null;
-      description = lib.mdDoc "The Git revision from which this NixOS configuration was built.";
-    };
+      codeName = mkOption {
+        readOnly = true;
+        type = types.str;
+        default = trivial.codeName;
+        description = lib.mdDoc "The NixOS release code name (e.g. `Emu`).";
+      };
 
-    nixos.codeName = mkOption {
-      readOnly = true;
-      type = types.str;
-      default = trivial.codeName;
-      description = lib.mdDoc "The NixOS release code name (e.g. `Emu`).";
-    };
+      distroId = mkOption {
+        internal = true;
+        type = types.str;
+        default = "nixos";
+        description = lib.mdDoc "The id of the operating system";
+      };
 
-    nixos.distroId = mkOption {
-      internal = true;
-      type = types.str;
-      default = "nixos";
-      description = lib.mdDoc "The id of the operating system";
-    };
+      distroName = mkOption {
+        internal = true;
+        type = types.str;
+        default = "NixOS";
+        description = lib.mdDoc "The name of the operating system";
+      };
 
-    nixos.distroName = mkOption {
-      internal = true;
-      type = types.str;
-      default = "NixOS";
-      description = lib.mdDoc "The name of the operating system";
+      variant_id = mkOption {
+        type = types.nullOr (types.strMatching "^[a-z0-9._-]+$");
+        default = null;
+        description = lib.mdDoc "A lower-case string identifying a specific variant or edition of the operating system";
+        example = "installer";
+      };
     };
 
-    nixos.variant_id = mkOption {
-      type = types.nullOr (types.strMatching "^[a-z0-9._-]+$");
-      default = null;
-      description = lib.mdDoc "A lower-case string identifying a specific variant or edition of the operating system";
-      example = "installer";
+    image = {
+
+      id = lib.mkOption {
+        type = types.nullOr (types.strMatching "^[a-z0-9._-]+$");
+        default = null;
+        description = lib.mdDoc ''
+          Image identifier.
+
+          This corresponds to the IMAGE_ID field in os-release. See the
+          upstream docs for more details on valid characters for this field:
+          https://www.freedesktop.org/software/systemd/man/latest/os-release.html#IMAGE_ID=
+
+          You would only want to set this option if you're build NixOS appliance images.
+        '';
+      };
+
+      version = lib.mkOption {
+        type = types.nullOr (types.strMatching "^[a-z0-9._-]+$");
+        default = null;
+        description = lib.mdDoc ''
+          Image version.
+
+          This corresponds to the IMAGE_VERSION field in os-release. See the
+          upstream docs for more details on valid characters for this field:
+          https://www.freedesktop.org/software/systemd/man/latest/os-release.html#IMAGE_VERSION=
+
+          You would only want to set this option if you're build NixOS appliance images.
+        '';
+      };
+
     };
 
     stateVersion = mkOption {
diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix
index 5f639e4e42e9..e81754414ea4 100644
--- a/nixpkgs/nixos/modules/module-list.nix
+++ b/nixpkgs/nixos/modules/module-list.nix
@@ -139,6 +139,7 @@
   ./programs/_1password-gui.nix
   ./programs/_1password.nix
   ./programs/adb.nix
+  ./programs/alvr.nix
   ./programs/appgate-sdp.nix
   ./programs/atop.nix
   ./programs/ausweisapp.nix
@@ -195,7 +196,6 @@
   ./programs/haguichi.nix
   ./programs/hamster.nix
   ./programs/htop.nix
-  ./programs/hyprland.nix
   ./programs/iay.nix
   ./programs/iftop.nix
   ./programs/i3lock.nix
@@ -215,9 +215,11 @@
   ./programs/minipro.nix
   ./programs/miriway.nix
   ./programs/mosh.nix
+  ./programs/mouse-actions.nix
   ./programs/msmtp.nix
   ./programs/mtr.nix
   ./programs/nano.nix
+  ./programs/nautilus-open-any-terminal.nix
   ./programs/nbd.nix
   ./programs/neovim.nix
   ./programs/nethoscope.nix
@@ -273,6 +275,7 @@
   ./programs/wavemon.nix
   ./programs/wayland/cardboard.nix
   ./programs/wayland/labwc.nix
+  ./programs/wayland/hyprland.nix
   ./programs/wayland/river.nix
   ./programs/wayland/sway.nix
   ./programs/wayland/waybar.nix
@@ -314,7 +317,6 @@
   ./security/oath.nix
   ./security/pam.nix
   ./security/pam_mount.nix
-  ./security/pam_usb.nix
   ./security/please.nix
   ./security/polkit.nix
   ./security/rngd.nix
@@ -408,7 +410,6 @@
   ./services/continuous-integration/buildbot/worker.nix
   ./services/continuous-integration/buildkite-agents.nix
   ./services/continuous-integration/gitea-actions-runner.nix
-  ./services/continuous-integration/github-runner.nix
   ./services/continuous-integration/github-runners.nix
   ./services/continuous-integration/gitlab-runner.nix
   ./services/continuous-integration/gocd-agent/default.nix
@@ -427,6 +428,7 @@
   ./services/databases/couchdb.nix
   ./services/databases/dgraph.nix
   ./services/databases/dragonflydb.nix
+  ./services/databases/etcd.nix
   ./services/databases/ferretdb.nix
   ./services/databases/firebird.nix
   ./services/databases/foundationdb.nix
@@ -446,6 +448,7 @@
   ./services/databases/postgresql.nix
   ./services/databases/redis.nix
   ./services/databases/surrealdb.nix
+  ./services/databases/tigerbeetle.nix
   ./services/databases/victoriametrics.nix
   ./services/desktops/accountsservice.nix
   ./services/desktops/ayatana-indicators.nix
@@ -506,7 +509,7 @@
   ./services/editors/haste.nix
   ./services/editors/infinoted.nix
   ./services/finance/odoo.nix
-  ./services/games/asf.nix
+  ./services/games/archisteamfarm.nix
   ./services/games/crossfire-server.nix
   ./services/games/deliantra-server.nix
   ./services/games/factorio.nix
@@ -533,6 +536,7 @@
   ./services/hardware/fancontrol.nix
   ./services/hardware/freefall.nix
   ./services/hardware/fwupd.nix
+  ./services/hardware/handheld-daemon.nix
   ./services/hardware/hddfancontrol.nix
   ./services/hardware/illum.nix
   ./services/hardware/interception-tools.nix
@@ -574,6 +578,7 @@
   ./services/home-automation/ebusd.nix
   ./services/home-automation/esphome.nix
   ./services/home-automation/evcc.nix
+  ./services/home-automation/govee2mqtt.nix
   ./services/home-automation/home-assistant.nix
   ./services/home-automation/homeassistant-satellite.nix
   ./services/home-automation/zigbee2mqtt.nix
@@ -634,6 +639,7 @@
   ./services/matrix/appservice-irc.nix
   ./services/matrix/conduit.nix
   ./services/matrix/dendrite.nix
+  ./services/matrix/hebbot.nix
   ./services/matrix/maubot.nix
   ./services/matrix/mautrix-facebook.nix
   ./services/matrix/mautrix-telegram.nix
@@ -675,7 +681,6 @@
   ./services/misc/dwm-status.nix
   ./services/misc/dysnomia.nix
   ./services/misc/errbot.nix
-  ./services/misc/etcd.nix
   ./services/misc/etebase-server.nix
   ./services/misc/etesync-dav.nix
   ./services/misc/evdevremapkeys.nix
@@ -833,6 +838,7 @@
   ./services/monitoring/riemann-dash.nix
   ./services/monitoring/riemann-tools.nix
   ./services/monitoring/riemann.nix
+  ./services/monitoring/rustdesk-server.nix
   ./services/monitoring/scollector.nix
   ./services/monitoring/smartd.nix
   ./services/monitoring/snmpd.nix
@@ -850,6 +856,7 @@
   ./services/monitoring/vmagent.nix
   ./services/monitoring/vmalert.nix
   ./services/monitoring/vnstat.nix
+  ./services/monitoring/watchdogd.nix
   ./services/monitoring/zabbix-agent.nix
   ./services/monitoring/zabbix-proxy.nix
   ./services/monitoring/zabbix-server.nix
@@ -1057,6 +1064,7 @@
   ./services/networking/openvpn.nix
   ./services/networking/ostinato.nix
   ./services/networking/owamp.nix
+  ./services/networking/pyload.nix
   ./services/networking/pdns-recursor.nix
   ./services/networking/pdnsd.nix
   ./services/networking/peroxide.nix
@@ -1195,6 +1203,7 @@
   ./services/security/hologram-agent.nix
   ./services/security/hologram-server.nix
   ./services/security/infnoise.nix
+  ./services/security/intune.nix
   ./services/security/jitterentropy-rngd.nix
   ./services/security/kanidm.nix
   ./services/security/munge.nix
@@ -1232,6 +1241,7 @@
   ./services/system/saslauthd.nix
   ./services/system/self-deploy.nix
   ./services/system/systembus-notify.nix
+  ./services/system/systemd-lock-handler.nix
   ./services/system/uptimed.nix
   ./services/system/zram-generator.nix
   ./services/torrent/deluge.nix
@@ -1336,10 +1346,11 @@
   ./services/web-apps/plantuml-server.nix
   ./services/web-apps/plausible.nix
   ./services/web-apps/powerdns-admin.nix
+  ./services/web-apps/pretalx.nix
   ./services/web-apps/prosody-filer.nix
-  ./services/web-apps/restya-board.nix
   ./services/web-apps/rimgo.nix
   ./services/web-apps/sftpgo.nix
+  ./services/web-apps/suwayomi-server.nix
   ./services/web-apps/rss-bridge.nix
   ./services/web-apps/selfoss.nix
   ./services/web-apps/shiori.nix
@@ -1467,6 +1478,7 @@
   ./system/boot/stratisroot.nix
   ./system/boot/modprobe.nix
   ./system/boot/networkd.nix
+  ./system/boot/uki.nix
   ./system/boot/unl0kr.nix
   ./system/boot/plymouth.nix
   ./system/boot/resolved.nix
@@ -1487,6 +1499,7 @@
   ./system/boot/systemd/repart.nix
   ./system/boot/systemd/shutdown.nix
   ./system/boot/systemd/sysupdate.nix
+  ./system/boot/systemd/sysusers.nix
   ./system/boot/systemd/tmpfiles.nix
   ./system/boot/systemd/user.nix
   ./system/boot/systemd/userdbd.nix
@@ -1513,7 +1526,9 @@
   ./tasks/filesystems/jfs.nix
   ./tasks/filesystems/nfs.nix
   ./tasks/filesystems/ntfs.nix
+  ./tasks/filesystems/overlayfs.nix
   ./tasks/filesystems/reiserfs.nix
+  ./tasks/filesystems/sshfs.nix
   ./tasks/filesystems/squashfs.nix
   ./tasks/filesystems/unionfs-fuse.nix
   ./tasks/filesystems/vboxsf.nix
diff --git a/nixpkgs/nixos/modules/profiles/hardened.nix b/nixpkgs/nixos/modules/profiles/hardened.nix
index 74dc2cb1b9aa..b85a2ac7e69d 100644
--- a/nixpkgs/nixos/modules/profiles/hardened.nix
+++ b/nixpkgs/nixos/modules/profiles/hardened.nix
@@ -39,14 +39,17 @@ with lib;
   security.apparmor.killUnconfinedConfinables = mkDefault true;
 
   boot.kernelParams = [
-    # Slab/slub sanity checks, redzoning, and poisoning
-    "slub_debug=FZP"
+    # Don't merge slabs
+    "slab_nomerge"
 
-    # Overwrite free'd memory
+    # Overwrite free'd pages
     "page_poison=1"
 
     # Enable page allocator randomization
     "page_alloc.shuffle=1"
+
+    # Disable debugfs
+    "debugfs=off"
   ];
 
   boot.blacklistedKernelModules = [
diff --git a/nixpkgs/nixos/modules/profiles/installation-device.nix b/nixpkgs/nixos/modules/profiles/installation-device.nix
index 58f07b050b5c..0b10c0414147 100644
--- a/nixpkgs/nixos/modules/profiles/installation-device.nix
+++ b/nixpkgs/nixos/modules/profiles/installation-device.nix
@@ -39,6 +39,9 @@ with lib;
     # Allow the user to log in as root without a password.
     users.users.root.initialHashedPassword = "";
 
+    # Don't require sudo/root to `reboot` or `poweroff`.
+    security.polkit.enable = true;
+
     # Allow passwordless sudo from nixos user
     security.sudo = {
       enable = mkDefault true;
diff --git a/nixpkgs/nixos/modules/profiles/perlless.nix b/nixpkgs/nixos/modules/profiles/perlless.nix
new file mode 100644
index 000000000000..90abd14f077e
--- /dev/null
+++ b/nixpkgs/nixos/modules/profiles/perlless.nix
@@ -0,0 +1,31 @@
+# WARNING: If you enable this profile, you will NOT be able to switch to a new
+# configuration and thus you will not be able to rebuild your system with
+# nixos-rebuild!
+
+{ lib, ... }:
+
+{
+
+  # Disable switching to a new configuration. This is not a necessary
+  # limitation of a perlless system but just a current one. In the future,
+  # perlless switching might be possible.
+  system.switch.enable = lib.mkDefault false;
+
+  # Remove perl from activation
+  boot.initrd.systemd.enable = lib.mkDefault true;
+  system.etc.overlay.enable = lib.mkDefault true;
+  systemd.sysusers.enable = lib.mkDefault true;
+
+  # Random perl remnants
+  system.disableInstallerTools = lib.mkDefault true;
+  programs.less.lessopen = lib.mkDefault null;
+  programs.command-not-found.enable = lib.mkDefault false;
+  boot.enableContainers = lib.mkDefault false;
+  environment.defaultPackages = lib.mkDefault [ ];
+  documentation.info.enable = lib.mkDefault false;
+
+  # Check that the system does not contain a Nix store path that contains the
+  # string "perl".
+  system.forbiddenDependenciesRegex = "perl";
+
+}
diff --git a/nixpkgs/nixos/modules/programs/alvr.nix b/nixpkgs/nixos/modules/programs/alvr.nix
new file mode 100644
index 000000000000..c01b74ad3a51
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/alvr.nix
@@ -0,0 +1,35 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.alvr;
+in
+{
+  options = {
+    programs.alvr = {
+      enable = mkEnableOption (lib.mdDoc "ALVR, the VR desktop streamer");
+
+      package = mkPackageOption pkgs "alvr" { };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Whether to open the default ports in the firewall for the ALVR server.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ cfg.package ];
+
+    networking.firewall = mkIf cfg.openFirewall {
+      allowedTCPPorts = [ 9943 9944 ];
+      allowedUDPPorts = [ 9943 9944 ];
+    };
+  };
+
+  meta.maintainers = with maintainers; [ passivelemon ];
+}
diff --git a/nixpkgs/nixos/modules/programs/chromium.nix b/nixpkgs/nixos/modules/programs/chromium.nix
index 4024f337dfcd..287d93c82cad 100644
--- a/nixpkgs/nixos/modules/programs/chromium.nix
+++ b/nixpkgs/nixos/modules/programs/chromium.nix
@@ -1,4 +1,4 @@
-{ config, lib, ... }:
+{ config, lib, pkgs, ... }:
 
 with lib;
 
@@ -21,8 +21,12 @@ in
     programs.chromium = {
       enable = mkEnableOption (lib.mdDoc "{command}`chromium` policies");
 
+      enablePlasmaBrowserIntegration = mkEnableOption (lib.mdDoc "Native Messaging Host for Plasma Browser Integration");
+
+      plasmaBrowserIntegrationPackage = mkPackageOption pkgs "plasma5Packages.plasma-browser-integration" { };
+
       extensions = mkOption {
-        type = types.listOf types.str;
+        type = with types; nullOr (listOf str);
         description = lib.mdDoc ''
           List of chromium extensions to install.
           For list of plugins ids see id in url of extensions on
@@ -33,7 +37,7 @@ in
           [ExtensionInstallForcelist](https://cloud.google.com/docs/chrome-enterprise/policies/?policy=ExtensionInstallForcelist)
           for additional details.
         '';
-        default = [];
+        default = null;
         example = literalExpression ''
           [
             "chlffgpmiacpedhhbkiomidkjlcfhogd" # pushbullet
@@ -62,16 +66,14 @@ in
         type = types.nullOr types.str;
         description = lib.mdDoc "Chromium default search provider url.";
         default = null;
-        example =
-          "https://encrypted.google.com/search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}ie={inputEncoding}";
+        example = "https://encrypted.google.com/search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}ie={inputEncoding}";
       };
 
       defaultSearchProviderSuggestURL = mkOption {
         type = types.nullOr types.str;
         description = lib.mdDoc "Chromium default search provider url for suggestions.";
         default = null;
-        example =
-          "https://encrypted.google.com/complete/search?output=chrome&q={searchTerms}";
+        example = "https://encrypted.google.com/complete/search?output=chrome&q={searchTerms}";
       };
 
       extraOpts = mkOption {
@@ -90,9 +92,9 @@ in
             "PasswordManagerEnabled" = false;
             "SpellcheckEnabled" = true;
             "SpellcheckLanguage" = [
-                                     "de"
-                                     "en-US"
-                                   ];
+              "de"
+              "en-US"
+            ];
           }
         '';
       };
@@ -101,15 +103,21 @@ in
 
   ###### implementation
 
-  config = lib.mkIf cfg.enable {
-    # for chromium
-    environment.etc."chromium/policies/managed/default.json".text = builtins.toJSON defaultProfile;
-    environment.etc."chromium/policies/managed/extra.json".text = builtins.toJSON cfg.extraOpts;
-    # for google-chrome https://www.chromium.org/administrators/linux-quick-start
-    environment.etc."opt/chrome/policies/managed/default.json".text = builtins.toJSON defaultProfile;
-    environment.etc."opt/chrome/policies/managed/extra.json".text = builtins.toJSON cfg.extraOpts;
-    # for brave
-    environment.etc."brave/policies/managed/default.json".text = builtins.toJSON defaultProfile;
-    environment.etc."brave/policies/managed/extra.json".text = builtins.toJSON cfg.extraOpts;
+  config = {
+    environment.etc = lib.mkIf cfg.enable {
+      # for chromium
+      "chromium/native-messaging-hosts/org.kde.plasma.browser_integration.json" = lib.mkIf cfg.enablePlasmaBrowserIntegration
+        { source = "${cfg.plasmaBrowserIntegrationPackage}/etc/chromium/native-messaging-hosts/org.kde.plasma.browser_integration.json"; };
+      "chromium/policies/managed/default.json" = lib.mkIf (defaultProfile != {}) { text = builtins.toJSON defaultProfile; };
+      "chromium/policies/managed/extra.json" = lib.mkIf (cfg.extraOpts != {}) { text = builtins.toJSON cfg.extraOpts; };
+      # for google-chrome https://www.chromium.org/administrators/linux-quick-start
+      "opt/chrome/native-messaging-hosts/org.kde.plasma.browser_integration.json" = lib.mkIf cfg.enablePlasmaBrowserIntegration
+        { source = "${cfg.plasmaBrowserIntegrationPackage}/etc/opt/chrome/native-messaging-hosts/org.kde.plasma.browser_integration.json"; };
+      "opt/chrome/policies/managed/default.json" = lib.mkIf (defaultProfile != {}) { text = builtins.toJSON defaultProfile; };
+      "opt/chrome/policies/managed/extra.json" = lib.mkIf (cfg.extraOpts != {}) { text = builtins.toJSON cfg.extraOpts; };
+      # for brave
+      "brave/policies/managed/default.json" = lib.mkIf (defaultProfile != {}) { text = builtins.toJSON defaultProfile; };
+      "brave/policies/managed/extra.json" = lib.mkIf (cfg.extraOpts != {}) { text = builtins.toJSON cfg.extraOpts; };
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/gamemode.nix b/nixpkgs/nixos/modules/programs/gamemode.nix
index 344f392852e2..2bb92ed8e0ef 100644
--- a/nixpkgs/nixos/modules/programs/gamemode.nix
+++ b/nixpkgs/nixos/modules/programs/gamemode.nix
@@ -90,6 +90,8 @@ in
         ];
       };
     };
+
+    users.groups.gamemode = { };
   };
 
   meta = {
diff --git a/nixpkgs/nixos/modules/programs/light.nix b/nixpkgs/nixos/modules/programs/light.nix
index 57cc925be465..1cdf22a7699d 100644
--- a/nixpkgs/nixos/modules/programs/light.nix
+++ b/nixpkgs/nixos/modules/programs/light.nix
@@ -9,6 +9,7 @@ in
 {
   options = {
     programs.light = {
+
       enable = mkOption {
         default = false;
         type = types.bool;
@@ -17,11 +18,60 @@ in
           and udev rules granting access to members of the "video" group.
         '';
       };
+
+      brightnessKeys = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Whether to enable brightness control with keyboard keys.
+
+            This is mainly useful for minimalistic (desktop) environments. You
+            may want to leave this disabled if you run a feature-rich desktop
+            environment such as KDE, GNOME or Xfce as those handle the
+            brightness keys themselves. However, enabling brightness control
+            with this setting makes the control independent of X, so the keys
+            work in non-graphical ttys, so you might want to consider using this
+            instead of the default offered by the desktop environment.
+
+            Enabling this will turn on {option}`services.actkbd`.
+          '';
+        };
+
+        step = mkOption {
+          type = types.int;
+          default = 10;
+          description = ''
+            The percentage value by which to increase/decrease brightness.
+          '';
+        };
+
+      };
+
     };
   };
 
   config = mkIf cfg.enable {
     environment.systemPackages = [ pkgs.light ];
     services.udev.packages = [ pkgs.light ];
+    services.actkbd = mkIf cfg.brightnessKeys.enable {
+      enable = true;
+      bindings = let
+        light = "${pkgs.light}/bin/light";
+        step = toString cfg.brightnessKeys.step;
+      in [
+        {
+          keys = [ 224 ];
+          events = [ "key" ];
+          # Use minimum brightness 0.1 so the display won't go totally black.
+          command = "${light} -N 0.1 && ${light} -U ${step}";
+        }
+        {
+          keys = [ 225 ];
+          events = [ "key" ];
+          command = "${light} -A ${step}";
+        }
+      ];
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/mouse-actions.nix b/nixpkgs/nixos/modules/programs/mouse-actions.nix
new file mode 100644
index 000000000000..fdf39d56d383
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/mouse-actions.nix
@@ -0,0 +1,15 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.programs.mouse-actions;
+in
+  {
+    options.programs.mouse-actions = {
+      enable = lib.mkEnableOption ''
+        mouse-actions udev rules. This is a prerequisite for using mouse-actions without being root.
+      '';
+    };
+    config = lib.mkIf cfg.enable {
+      services.udev.packages = [ pkgs.mouse-actions ];
+    };
+  }
diff --git a/nixpkgs/nixos/modules/programs/nautilus-open-any-terminal.nix b/nixpkgs/nixos/modules/programs/nautilus-open-any-terminal.nix
new file mode 100644
index 000000000000..d205fb3ec916
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/nautilus-open-any-terminal.nix
@@ -0,0 +1,36 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.programs.nautilus-open-any-terminal;
+in
+{
+  options.programs.nautilus-open-any-terminal = {
+    enable = lib.mkEnableOption (lib.mdDoc "nautilus-open-any-terminal");
+
+    terminal = lib.mkOption {
+      type = with lib.types; nullOr str;
+      default = null;
+      description = lib.mdDoc ''
+        The terminal emulator to add to context-entry of nautilus. Supported terminal
+        emulators are listed in https://github.com/Stunkymonkey/nautilus-open-any-terminal#supported-terminal-emulators.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    environment.systemPackages = with pkgs; [
+      gnome.nautilus-python
+      nautilus-open-any-terminal
+    ];
+    programs.dconf = lib.optionalAttrs (cfg.terminal != null) {
+      enable = true;
+      profiles.user.databases = [{
+        settings."com/github/stunkymonkey/nautilus-open-any-terminal".terminal = cfg.terminal;
+        lockAll = true;
+      }];
+    };
+  };
+  meta = {
+    maintainers = with lib.maintainers; [ stunkymonkey linsui ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/programs/regreet.nix b/nixpkgs/nixos/modules/programs/regreet.nix
index 0c44d717044e..55d0c11781ab 100644
--- a/nixpkgs/nixos/modules/programs/regreet.nix
+++ b/nixpkgs/nixos/modules/programs/regreet.nix
@@ -78,11 +78,15 @@ in
         else settingsFormat.generate "regreet.toml" cfg.settings;
     };
 
-    systemd.tmpfiles.rules = let
-      group = config.users.users.${config.services.greetd.settings.default_session.user}.group;
-    in [
-      "d /var/log/regreet 0755 greeter ${group} - -"
-      "d /var/cache/regreet 0755 greeter ${group} - -"
-    ];
+    systemd.tmpfiles.settings."10-regreet" = let
+      defaultConfig = {
+        user = "greeter";
+        group = config.users.users.${config.services.greetd.settings.default_session.user}.group;
+        mode = "0755";
+      };
+    in {
+      "/var/log/regreet".d = defaultConfig;
+      "/var/cache/regreet".d = defaultConfig;
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/ssh.nix b/nixpkgs/nixos/modules/programs/ssh.nix
index c39a3c8d509b..0c1461709c22 100644
--- a/nixpkgs/nixos/modules/programs/ssh.nix
+++ b/nixpkgs/nixos/modules/programs/ssh.nix
@@ -12,6 +12,7 @@ let
     ''
       #! ${pkgs.runtimeShell} -e
       export DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^DISPLAY=\(.*\)/\1/; t; d')"
+      export XAUTHORITY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^XAUTHORITY=\(.*\)/\1/; t; d')"
       export WAYLAND_DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^WAYLAND_DISPLAY=\(.*\)/\1/; t; d')"
       exec ${cfg.askPassword} "$@"
     '';
diff --git a/nixpkgs/nixos/modules/programs/tsm-client.nix b/nixpkgs/nixos/modules/programs/tsm-client.nix
index 45d436221ee3..d31a1fb3f375 100644
--- a/nixpkgs/nixos/modules/programs/tsm-client.nix
+++ b/nixpkgs/nixos/modules/programs/tsm-client.nix
@@ -22,7 +22,7 @@ let
   serverOptions = { name, config, ... }: {
     freeformType = attrsOf (either scalarType (listOf scalarType));
     # Client system-options file directives are explained here:
-    # https://www.ibm.com/docs/en/storage-protect/8.1.20?topic=commands-processing-options
+    # https://www.ibm.com/docs/en/storage-protect/8.1.21?topic=commands-processing-options
     options.servername = mkOption {
       type = servernameType;
       default = name;
diff --git a/nixpkgs/nixos/modules/programs/hyprland.nix b/nixpkgs/nixos/modules/programs/wayland/hyprland.nix
index 9061ce5da83a..9061ce5da83a 100644
--- a/nixpkgs/nixos/modules/programs/hyprland.nix
+++ b/nixpkgs/nixos/modules/programs/wayland/hyprland.nix
diff --git a/nixpkgs/nixos/modules/rename.nix b/nixpkgs/nixos/modules/rename.nix
index 3fab863adb7f..0a975fcd98c8 100644
--- a/nixpkgs/nixos/modules/rename.nix
+++ b/nixpkgs/nixos/modules/rename.nix
@@ -112,6 +112,7 @@ in
     (mkRemovedOptionModule [ "services" "cryptpad" ] "The corresponding package was removed from nixpkgs.")
     (mkRemovedOptionModule [ "services" "rtsp-simple-server" ] "Package has been completely rebranded by upstream as mediamtx, and thus the service and the package were renamed in NixOS as well.")
     (mkRemovedOptionModule [ "services" "prayer" ] "The corresponding package was removed from nixpkgs.")
+    (mkRemovedOptionModule [ "services" "restya-board" ] "The corresponding package was removed from nixpkgs.")
 
     (mkRemovedOptionModule [ "i18n" "inputMethod" "fcitx" ] "The fcitx module has been removed. Please use fcitx5 instead")
     (mkRemovedOptionModule [ "services" "dhcpd4" ] ''
diff --git a/nixpkgs/nixos/modules/security/acme/default.nix b/nixpkgs/nixos/modules/security/acme/default.nix
index 7cc302969fb6..19297d267851 100644
--- a/nixpkgs/nixos/modules/security/acme/default.nix
+++ b/nixpkgs/nixos/modules/security/acme/default.nix
@@ -545,12 +545,14 @@ let
       };
 
       server = mkOption {
-        type = types.nullOr types.str;
-        inherit (defaultAndText "server" null) default defaultText;
+        type = types.str;
+        inherit (defaultAndText "server" "https://acme-v02.api.letsencrypt.org/directory") default defaultText;
+        example = "https://acme-staging-v02.api.letsencrypt.org/directory";
         description = lib.mdDoc ''
-          ACME Directory Resource URI. Defaults to Let's Encrypt's
-          production endpoint,
-          <https://acme-v02.api.letsencrypt.org/directory>, if unset.
+          ACME Directory Resource URI.
+          Defaults to Let's Encrypt's production endpoint.
+          For testing Let's Encrypt's [staging endpoint](https://letsencrypt.org/docs/staging-environment/)
+          should be used to avoid the rather tight rate limit on the production endpoint.
         '';
       };
 
@@ -897,10 +899,10 @@ in {
         certs = attrValues cfg.certs;
       in [
         {
-          assertion = cfg.email != null || all (certOpts: certOpts.email != null) certs;
+          assertion = cfg.defaults.email != null || all (certOpts: certOpts.email != null) certs;
           message = ''
             You must define `security.acme.certs.<name>.email` or
-            `security.acme.email` to register with the CA. Note that using
+            `security.acme.defaults.email` to register with the CA. Note that using
             many different addresses for certs may trigger account rate limits.
           '';
         }
diff --git a/nixpkgs/nixos/modules/security/pam.nix b/nixpkgs/nixos/modules/security/pam.nix
index 111be7057afc..ed03254cb5ee 100644
--- a/nixpkgs/nixos/modules/security/pam.nix
+++ b/nixpkgs/nixos/modules/security/pam.nix
@@ -205,17 +205,6 @@ let
         };
       };
 
-      usbAuth = mkOption {
-        default = config.security.pam.usb.enable;
-        defaultText = literalExpression "config.security.pam.usb.enable";
-        type = types.bool;
-        description = lib.mdDoc ''
-          If set, users listed in
-          {file}`/etc/pamusb.conf` are able to log in
-          with the associated USB key.
-        '';
-      };
-
       otpwAuth = mkOption {
         default = config.security.pam.enableOTPW;
         defaultText = literalExpression "config.security.pam.enableOTPW";
@@ -665,7 +654,6 @@ let
             authfile = u2f.authFile;
             appid = u2f.appId;
           }; })
-          { name = "usb"; enable = cfg.usbAuth; control = "sufficient"; modulePath = "${pkgs.pam_usb}/lib/security/pam_usb.so"; }
           (let ussh = config.security.pam.ussh; in { name = "ussh"; enable = config.security.pam.ussh.enable && cfg.usshAuth; control = ussh.control; modulePath = "${pkgs.pam_ussh}/lib/security/pam_ussh.so"; settings = {
             ca_file = ussh.caFile;
             authorized_principals = ussh.authorizedPrincipals;
@@ -700,6 +688,7 @@ let
               || cfg.pamMount
               || cfg.enableKwallet
               || cfg.enableGnomeKeyring
+              || config.services.intune.enable
               || cfg.googleAuthenticator.enable
               || cfg.gnupg.enable
               || cfg.failDelay.enable
@@ -726,6 +715,7 @@ let
                 kwalletd = "${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5";
               }; }
               { name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so"; }
+              { name = "intune"; enable = config.services.intune.enable; control = "optional"; modulePath = "${pkgs.intune-portal}/lib/security/pam_intune.so"; }
               { name = "gnupg"; enable = cfg.gnupg.enable; control = "optional"; modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; settings = {
                 store-only = cfg.gnupg.storeOnly;
               }; }
@@ -867,9 +857,7 @@ let
           { name = "gnupg"; enable = cfg.gnupg.enable; control = "optional"; modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; settings = {
             no-autostart = cfg.gnupg.noAutostart;
           }; }
-          { name = "cgfs"; enable = config.virtualisation.lxc.lxcfs.enable; control = "optional"; modulePath = "${pkgs.lxc}/lib/security/pam_cgfs.so"; args = [
-            "-c" "all"
-          ]; }
+          { name = "intune"; enable = config.services.intune.enable; control = "optional"; modulePath = "${pkgs.intune-portal}/lib/security/pam_intune.so"; }
         ];
       };
     };
diff --git a/nixpkgs/nixos/modules/security/pam_usb.nix b/nixpkgs/nixos/modules/security/pam_usb.nix
deleted file mode 100644
index 4275c26c6bda..000000000000
--- a/nixpkgs/nixos/modules/security/pam_usb.nix
+++ /dev/null
@@ -1,51 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  cfg = config.security.pam.usb;
-
-  anyUsbAuth = any (attrByPath ["usbAuth"] false) (attrValues config.security.pam.services);
-
-in
-
-{
-  options = {
-
-    security.pam.usb = {
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Enable USB login for all login systems that support it.  For
-          more information, visit <https://github.com/aluzzardi/pam_usb/wiki/Getting-Started#setting-up-devices-and-users>.
-        '';
-      };
-
-    };
-
-  };
-
-  config = mkIf (cfg.enable || anyUsbAuth) {
-
-    # Make sure pmount and pumount are setuid wrapped.
-    security.wrappers = {
-      pmount =
-        { setuid = true;
-          owner = "root";
-          group = "root";
-          source = "${pkgs.pmount.out}/bin/pmount";
-        };
-      pumount =
-        { setuid = true;
-          owner = "root";
-          group = "root";
-          source = "${pkgs.pmount.out}/bin/pumount";
-        };
-    };
-
-    environment.systemPackages = [ pkgs.pmount ];
-
-  };
-}
diff --git a/nixpkgs/nixos/modules/security/wrappers/wrapper.c b/nixpkgs/nixos/modules/security/wrappers/wrapper.c
index 3277e7ef6f79..3e126875c687 100644
--- a/nixpkgs/nixos/modules/security/wrappers/wrapper.c
+++ b/nixpkgs/nixos/modules/security/wrappers/wrapper.c
@@ -172,6 +172,13 @@ static int make_caps_ambient(const char *self_path) {
 int main(int argc, char **argv) {
     ASSERT(argc >= 1);
 
+    // argv[0] goes into a lot of places, to a far greater degree than other elements
+    // of argv. glibc has had buffer overflows relating to argv[0], eg CVE-2023-6246.
+    // Since we expect the wrappers to be invoked from either $PATH or /run/wrappers/bin,
+    // there should be no reason to pass any particularly large values here, so we can
+    // be strict for strictness' sake.
+    ASSERT(strlen(argv[0]) < 512);
+
     int debug = getenv(wrapper_debug) != NULL;
 
     // Drop insecure environment variables explicitly
diff --git a/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix b/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix
index 7dce9d242916..f2dee07c91ab 100644
--- a/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix
+++ b/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix
@@ -14,6 +14,15 @@ let
 
 in
 {
+
+  imports = [
+    (mkRemovedOptionModule [ "services" "rabbitmq" "cookie" ] ''
+      This option wrote the Erlang cookie to the store, while it should be kept secret.
+      Please remove it from your NixOS configuration and deploy a cookie securely instead.
+      The renamed `unsafeCookie` must ONLY be used in isolated non-production environments such as NixOS VM tests.
+    '')
+  ];
+
   ###### interface
   options = {
     services.rabbitmq = {
@@ -62,13 +71,18 @@ in
         '';
       };
 
-      cookie = mkOption {
+      unsafeCookie = mkOption {
         default = "";
         type = types.str;
         description = lib.mdDoc ''
           Erlang cookie is a string of arbitrary length which must
           be the same for several nodes to be allowed to communicate.
           Leave empty to generate automatically.
+
+          Setting the cookie via this option exposes the cookie to the store, which
+          is not recommended for security reasons.
+          Only use this option in an isolated non-production environment such as
+          NixOS VM tests.
         '';
       };
 
@@ -209,9 +223,8 @@ in
       };
 
       preStart = ''
-        ${optionalString (cfg.cookie != "") ''
-            echo -n ${cfg.cookie} > ${cfg.dataDir}/.erlang.cookie
-            chmod 600 ${cfg.dataDir}/.erlang.cookie
+        ${optionalString (cfg.unsafeCookie != "") ''
+          install -m 600 <(echo -n ${cfg.unsafeCookie}) ${cfg.dataDir}/.erlang.cookie
         ''}
       '';
     };
diff --git a/nixpkgs/nixos/modules/services/audio/gmediarender.nix b/nixpkgs/nixos/modules/services/audio/gmediarender.nix
index 545f2b1a2b60..a4cb89098db7 100644
--- a/nixpkgs/nixos/modules/services/audio/gmediarender.nix
+++ b/nixpkgs/nixos/modules/services/audio/gmediarender.nix
@@ -64,6 +64,7 @@ in
   config = mkIf cfg.enable {
     systemd = {
       services.gmediarender = {
+        wants = [ "network-online.target" ];
         after = [ "network-online.target" ];
         wantedBy = [ "multi-user.target" ];
         description = "gmediarender server daemon";
diff --git a/nixpkgs/nixos/modules/services/audio/jmusicbot.nix b/nixpkgs/nixos/modules/services/audio/jmusicbot.nix
index fd1d4da19284..e7803677d0fd 100644
--- a/nixpkgs/nixos/modules/services/audio/jmusicbot.nix
+++ b/nixpkgs/nixos/modules/services/audio/jmusicbot.nix
@@ -26,6 +26,7 @@ in
   config = mkIf cfg.enable {
     systemd.services.jmusicbot = {
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       description = "Discord music bot that's easy to set up and run yourself!";
       serviceConfig = mkMerge [{
diff --git a/nixpkgs/nixos/modules/services/audio/mopidy.nix b/nixpkgs/nixos/modules/services/audio/mopidy.nix
index 9d8e67b0ea47..8eebf0f9d1e1 100644
--- a/nixpkgs/nixos/modules/services/audio/mopidy.nix
+++ b/nixpkgs/nixos/modules/services/audio/mopidy.nix
@@ -70,9 +70,10 @@ in {
 
   config = mkIf cfg.enable {
 
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' - mopidy mopidy - -"
-    ];
+    systemd.tmpfiles.settings."10-mopidy".${cfg.dataDir}.d = {
+      user = "mopidy";
+      group = "mopidy";
+    };
 
     systemd.services.mopidy = {
       wantedBy = [ "multi-user.target" ];
diff --git a/nixpkgs/nixos/modules/services/audio/navidrome.nix b/nixpkgs/nixos/modules/services/audio/navidrome.nix
index e44fc822e4ad..912edb03aa4c 100644
--- a/nixpkgs/nixos/modules/services/audio/navidrome.nix
+++ b/nixpkgs/nixos/modules/services/audio/navidrome.nix
@@ -53,6 +53,7 @@ in {
         RuntimeDirectory = "navidrome";
         RootDirectory = "/run/navidrome";
         ReadWritePaths = "";
+        BindPaths = lib.optional (cfg.settings ? DataFolder) cfg.settings.DataFolder;
         BindReadOnlyPaths = [
           # navidrome uses online services to download additional album metadata / covers
           "${config.environment.etc."ssl/certs/ca-certificates.crt".source}:/etc/ssl/certs/ca-certificates.crt"
diff --git a/nixpkgs/nixos/modules/services/audio/spotifyd.nix b/nixpkgs/nixos/modules/services/audio/spotifyd.nix
index 975be5a87cba..1194b6f200d7 100644
--- a/nixpkgs/nixos/modules/services/audio/spotifyd.nix
+++ b/nixpkgs/nixos/modules/services/audio/spotifyd.nix
@@ -50,6 +50,7 @@ in
 
     systemd.services.spotifyd = {
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" "sound.target" ];
       description = "spotifyd, a Spotify playing daemon";
       environment.SHELL = "/bin/sh";
diff --git a/nixpkgs/nixos/modules/services/audio/ympd.nix b/nixpkgs/nixos/modules/services/audio/ympd.nix
index b74cc3f9c0b4..6e8d22dab3c8 100644
--- a/nixpkgs/nixos/modules/services/audio/ympd.nix
+++ b/nixpkgs/nixos/modules/services/audio/ympd.nix
@@ -50,6 +50,7 @@ in {
       description = "Standalone MPD Web GUI written in C";
 
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
 
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/backup/tsm.nix b/nixpkgs/nixos/modules/services/backup/tsm.nix
index 6798b18b3af7..2d727dccdece 100644
--- a/nixpkgs/nixos/modules/services/backup/tsm.nix
+++ b/nixpkgs/nixos/modules/services/backup/tsm.nix
@@ -90,7 +90,7 @@ in
       environment.HOME = "/var/lib/tsm-backup";
       serviceConfig = {
         # for exit status description see
-        # https://www.ibm.com/docs/en/storage-protect/8.1.20?topic=clients-client-return-codes
+        # https://www.ibm.com/docs/en/storage-protect/8.1.21?topic=clients-client-return-codes
         SuccessExitStatus = "4 8";
         # The `-se` option must come after the command.
         # The `-optfile` option suppresses a `dsm.opt`-not-found warning.
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix
index 35151ebd6bd7..9a01238c2391 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix
@@ -174,9 +174,8 @@ in
       '')
       (optionalString cfg.genCfsslAPIToken ''
         if [ ! -f "${cfsslAPITokenPath}" ]; then
-          head -c ${toString (cfsslAPITokenLength / 2)} /dev/urandom | od -An -t x | tr -d ' ' >"${cfsslAPITokenPath}"
+          install -o cfssl -m 400 <(head -c ${toString (cfsslAPITokenLength / 2)} /dev/urandom | od -An -t x | tr -d ' ') "${cfsslAPITokenPath}"
         fi
-        chown cfssl "${cfsslAPITokenPath}" && chmod 400 "${cfsslAPITokenPath}"
       '')]);
 
     systemd.services.kube-certmgr-bootstrap = {
@@ -194,7 +193,7 @@ in
         if [ -f "${cfsslAPITokenPath}" ]; then
           ln -fs "${cfsslAPITokenPath}" "${certmgrAPITokenPath}"
         else
-          touch "${certmgrAPITokenPath}" && chmod 600 "${certmgrAPITokenPath}"
+          install -m 600 /dev/null "${certmgrAPITokenPath}"
         fi
       ''
       (optionalString (cfg.pkiTrustOnBootstrap) ''
@@ -220,7 +219,6 @@ in
             inherit (cert) action;
             authority = {
               inherit remote;
-              file.path = cert.caCert;
               root_ca = cert.caCert;
               profile = "default";
               auth_key_file = certmgrAPITokenPath;
@@ -297,8 +295,7 @@ in
           exit 1
         fi
 
-        echo $token > ${certmgrAPITokenPath}
-        chmod 600 ${certmgrAPITokenPath}
+        install -m 0600 <(echo $token) ${certmgrAPITokenPath}
 
         echo "Restarting certmgr..." >&1
         systemctl restart certmgr
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixpkgs/nixos/modules/services/continuous-integration/buildbot/master.nix
index 446d19b8fd5a..9f702b17937c 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/buildbot/master.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/buildbot/master.nix
@@ -267,7 +267,7 @@ in {
 
     systemd.services.buildbot-master = {
       description = "Buildbot Continuous Integration Server.";
-      after = [ "network-online.target" ];
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       path = cfg.packages ++ cfg.pythonPackages python.pkgs;
       environment.PYTHONPATH = "${python.withPackages (self: cfg.pythonPackages self ++ [ package ])}/${python.sitePackages}";
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/gitea-actions-runner.nix b/nixpkgs/nixos/modules/services/continuous-integration/gitea-actions-runner.nix
index 3f2be9464849..06f0da3451a6 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/gitea-actions-runner.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/gitea-actions-runner.nix
@@ -188,6 +188,7 @@ in
         nameValuePair "gitea-runner-${escapeSystemdPath name}" {
           inherit (instance) enable;
           description = "Gitea Actions Runner";
+          wants = [ "network-online.target" ];
           after = [
             "network-online.target"
           ] ++ optionals (wantsDocker) [
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/github-runner.nix b/nixpkgs/nixos/modules/services/continuous-integration/github-runner.nix
deleted file mode 100644
index 27cfee92c75a..000000000000
--- a/nixpkgs/nixos/modules/services/continuous-integration/github-runner.nix
+++ /dev/null
@@ -1,25 +0,0 @@
-{ config
-, pkgs
-, lib
-, ...
-}@args:
-
-with lib;
-
-let
-  cfg = config.services.github-runner;
-in
-
-{
-  options.services.github-runner = import ./github-runner/options.nix (args // {
-    # Users don't need to specify options.services.github-runner.name; it will default
-    # to the hostname.
-    includeNameDefault = true;
-  });
-
-  config = mkIf cfg.enable {
-    services.github-runners.${cfg.name} = cfg;
-  };
-
-  meta.maintainers = with maintainers; [ veehaitch newam thomasjm ];
-}
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/github-runner/options.nix b/nixpkgs/nixos/modules/services/continuous-integration/github-runner/options.nix
index 2335826e8b66..193261fc2a9f 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/github-runner/options.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/github-runner/options.nix
@@ -1,212 +1,266 @@
-{ config
-, lib
+{ lib
 , pkgs
-, includeNameDefault
 , ...
 }:
 
 with lib;
-
 {
-  enable = mkOption {
-    default = false;
-    example = true;
-    description = lib.mdDoc ''
-      Whether to enable GitHub Actions runner.
-
-      Note: GitHub recommends using self-hosted runners with private repositories only. Learn more here:
-      [About self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners).
-    '';
-    type = lib.types.bool;
-  };
-
-  url = mkOption {
-    type = types.str;
-    description = lib.mdDoc ''
-      Repository to add the runner to.
-
-      Changing this option triggers a new runner registration.
-
-      IMPORTANT: If your token is org-wide (not per repository), you need to
-      provide a github org link, not a single repository, so do it like this
-      `https://github.com/nixos`, not like this
-      `https://github.com/nixos/nixpkgs`.
-      Otherwise, you are going to get a `404 NotFound`
-      from `POST https://api.github.com/actions/runner-registration`
-      in the configure script.
-    '';
-    example = "https://github.com/nixos/nixpkgs";
-  };
-
-  tokenFile = mkOption {
-    type = types.path;
-    description = lib.mdDoc ''
-      The full path to a file which contains either
-
-      * a fine-grained personal access token (PAT),
-      * a classic PAT
-      * or a runner registration token
-
-      Changing this option or the `tokenFile`’s content triggers a new runner registration.
-
-      We suggest using the fine-grained PATs. A runner registration token is valid
-      only for 1 hour after creation, so the next time the runner configuration changes
-      this will give you hard-to-debug HTTP 404 errors in the configure step.
-
-      The file should contain exactly one line with the token without any newline.
-      (Use `echo -n '…token…' > …token file…` to make sure no newlines sneak in.)
-
-      If the file contains a PAT, the service creates a new registration token
-      on startup as needed.
-      If a registration token is given, it can be used to re-register a runner of the same
-      name but is time-limited as noted above.
-
-      For fine-grained PATs:
-
-      Give it "Read and Write access to organization/repository self hosted runners",
-      depending on whether it is organization wide or per-repository. You might have to
-      experiment a little, fine-grained PATs are a `beta` Github feature and still subject
-      to change; nonetheless they are the best option at the moment.
-
-      For classic PATs:
-
-      Make sure the PAT has a scope of `admin:org` for organization-wide registrations
-      or a scope of `repo` for a single repository.
-
-      For runner registration tokens:
-
-      Nothing special needs to be done, but updating will break after one hour,
-      so these are not recommended.
-    '';
-    example = "/run/secrets/github-runner/nixos.token";
-  };
-
-  name = let
-    # Same pattern as for `networking.hostName`
-    baseType = types.strMatching "^$|^[[:alnum:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$";
-  in mkOption {
-    type = if includeNameDefault then baseType else types.nullOr baseType;
-    description = lib.mdDoc ''
-      Name of the runner to configure. Defaults to the hostname.
-
-      Changing this option triggers a new runner registration.
-    '';
-    example = "nixos";
-  } // (if includeNameDefault then {
-    default = config.networking.hostName;
-    defaultText = literalExpression "config.networking.hostName";
-  } else {
-    default = null;
-  });
-
-  runnerGroup = mkOption {
-    type = types.nullOr types.str;
-    description = lib.mdDoc ''
-      Name of the runner group to add this runner to (defaults to the default runner group).
-
-      Changing this option triggers a new runner registration.
-    '';
-    default = null;
-  };
-
-  extraLabels = mkOption {
-    type = types.listOf types.str;
-    description = lib.mdDoc ''
-      Extra labels in addition to the default (`["self-hosted", "Linux", "X64"]`).
-
-      Changing this option triggers a new runner registration.
-    '';
-    example = literalExpression ''[ "nixos" ]'';
-    default = [ ];
-  };
-
-  replace = mkOption {
-    type = types.bool;
-    description = lib.mdDoc ''
-      Replace any existing runner with the same name.
-
-      Without this flag, registering a new runner with the same name fails.
-    '';
-    default = false;
-  };
-
-  extraPackages = mkOption {
-    type = types.listOf types.package;
-    description = lib.mdDoc ''
-      Extra packages to add to `PATH` of the service to make them available to workflows.
-    '';
-    default = [ ];
-  };
-
-  extraEnvironment = mkOption {
-    type = types.attrs;
-    description = lib.mdDoc ''
-      Extra environment variables to set for the runner, as an attrset.
-    '';
-    example = {
-      GIT_CONFIG = "/path/to/git/config";
-    };
-    default = {};
-  };
-
-  serviceOverrides = mkOption {
-    type = types.attrs;
-    description = lib.mdDoc ''
-      Modify the systemd service. Can be used to, e.g., adjust the sandboxing options.
+  options.services.github-runners = mkOption {
+    description = mdDoc ''
+      Multiple GitHub Runners.
     '';
     example = {
-      ProtectHome = false;
-      RestrictAddressFamilies = [ "AF_PACKET" ];
+      runner1 = {
+        enable = true;
+        url = "https://github.com/owner/repo";
+        name = "runner1";
+        tokenFile = "/secrets/token1";
+      };
+
+      runner2 = {
+        enable = true;
+        url = "https://github.com/owner/repo";
+        name = "runner2";
+        tokenFile = "/secrets/token2";
+      };
     };
-    default = {};
-  };
-
-  package = mkPackageOption pkgs "github-runner" { };
-
-  ephemeral = mkOption {
-    type = types.bool;
-    description = lib.mdDoc ''
-      If enabled, causes the following behavior:
-
-      - Passes the `--ephemeral` flag to the runner configuration script
-      - De-registers and stops the runner with GitHub after it has processed one job
-      - On stop, systemd wipes the runtime directory (this always happens, even without using the ephemeral option)
-      - Restarts the service after its successful exit
-      - On start, wipes the state directory and configures a new runner
-
-      You should only enable this option if `tokenFile` points to a file which contains a
-      personal access token (PAT). If you're using the option with a registration token, restarting the
-      service will fail as soon as the registration token expired.
-    '';
-    default = false;
-  };
-
-  user = mkOption {
-    type = types.nullOr types.str;
-    description = lib.mdDoc ''
-      User under which to run the service. If null, will use a systemd dynamic user.
-    '';
-    default = null;
-    defaultText = literalExpression "username";
-  };
-
-  workDir = mkOption {
-    type = with types; nullOr str;
-    description = lib.mdDoc ''
-      Working directory, available as `$GITHUB_WORKSPACE` during workflow runs
-      and used as a default for [repository checkouts](https://github.com/actions/checkout).
-      The service cleans this directory on every service start.
-
-      A value of `null` will default to the systemd `RuntimeDirectory`.
-    '';
-    default = null;
-  };
-
-  nodeRuntimes = mkOption {
-    type = with types; nonEmptyListOf (enum [ "node16" "node20" ]);
-    default = [ "node20" ];
-    description = mdDoc ''
-      List of Node.js runtimes the runner should support.
-    '';
+    default = { };
+    type = types.attrsOf (types.submodule ({ name, ... }: {
+      options = {
+        enable = mkOption {
+          default = false;
+          example = true;
+          description = mdDoc ''
+            Whether to enable GitHub Actions runner.
+
+            Note: GitHub recommends using self-hosted runners with private repositories only. Learn more here:
+            [About self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners).
+          '';
+          type = types.bool;
+        };
+
+        url = mkOption {
+          type = types.str;
+          description = mdDoc ''
+            Repository to add the runner to.
+
+            Changing this option triggers a new runner registration.
+
+            IMPORTANT: If your token is org-wide (not per repository), you need to
+            provide a github org link, not a single repository, so do it like this
+            `https://github.com/nixos`, not like this
+            `https://github.com/nixos/nixpkgs`.
+            Otherwise, you are going to get a `404 NotFound`
+            from `POST https://api.github.com/actions/runner-registration`
+            in the configure script.
+          '';
+          example = "https://github.com/nixos/nixpkgs";
+        };
+
+        tokenFile = mkOption {
+          type = types.path;
+          description = mdDoc ''
+            The full path to a file which contains either
+
+            * a fine-grained personal access token (PAT),
+            * a classic PAT
+            * or a runner registration token
+
+            Changing this option or the `tokenFile`’s content triggers a new runner registration.
+
+            We suggest using the fine-grained PATs. A runner registration token is valid
+            only for 1 hour after creation, so the next time the runner configuration changes
+            this will give you hard-to-debug HTTP 404 errors in the configure step.
+
+            The file should contain exactly one line with the token without any newline.
+            (Use `echo -n '…token…' > …token file…` to make sure no newlines sneak in.)
+
+            If the file contains a PAT, the service creates a new registration token
+            on startup as needed.
+            If a registration token is given, it can be used to re-register a runner of the same
+            name but is time-limited as noted above.
+
+            For fine-grained PATs:
+
+            Give it "Read and Write access to organization/repository self hosted runners",
+            depending on whether it is organization wide or per-repository. You might have to
+            experiment a little, fine-grained PATs are a `beta` Github feature and still subject
+            to change; nonetheless they are the best option at the moment.
+
+            For classic PATs:
+
+            Make sure the PAT has a scope of `admin:org` for organization-wide registrations
+            or a scope of `repo` for a single repository.
+
+            For runner registration tokens:
+
+            Nothing special needs to be done, but updating will break after one hour,
+            so these are not recommended.
+          '';
+          example = "/run/secrets/github-runner/nixos.token";
+        };
+
+        name = mkOption {
+          type = types.nullOr types.str;
+          description = mdDoc ''
+            Name of the runner to configure. If null, defaults to the hostname.
+
+            Changing this option triggers a new runner registration.
+          '';
+          example = "nixos";
+          default = name;
+        };
+
+        runnerGroup = mkOption {
+          type = types.nullOr types.str;
+          description = mdDoc ''
+            Name of the runner group to add this runner to (defaults to the default runner group).
+
+            Changing this option triggers a new runner registration.
+          '';
+          default = null;
+        };
+
+        extraLabels = mkOption {
+          type = types.listOf types.str;
+          description = mdDoc ''
+            Extra labels in addition to the default (unless disabled through the `noDefaultLabels` option).
+
+            Changing this option triggers a new runner registration.
+          '';
+          example = literalExpression ''[ "nixos" ]'';
+          default = [ ];
+        };
+
+        noDefaultLabels = mkOption {
+          type = types.bool;
+          description = mdDoc ''
+            Disables adding the default labels. Also see the `extraLabels` option.
+
+            Changing this option triggers a new runner registration.
+          '';
+          default = false;
+        };
+
+        replace = mkOption {
+          type = types.bool;
+          description = mdDoc ''
+            Replace any existing runner with the same name.
+
+            Without this flag, registering a new runner with the same name fails.
+          '';
+          default = false;
+        };
+
+        extraPackages = mkOption {
+          type = types.listOf types.package;
+          description = mdDoc ''
+            Extra packages to add to `PATH` of the service to make them available to workflows.
+          '';
+          default = [ ];
+        };
+
+        extraEnvironment = mkOption {
+          type = types.attrs;
+          description = mdDoc ''
+            Extra environment variables to set for the runner, as an attrset.
+          '';
+          example = {
+            GIT_CONFIG = "/path/to/git/config";
+          };
+          default = { };
+        };
+
+        serviceOverrides = mkOption {
+          type = types.attrs;
+          description = mdDoc ''
+            Modify the systemd service. Can be used to, e.g., adjust the sandboxing options.
+            See {manpage}`systemd.exec(5)` for more options.
+          '';
+          example = {
+            ProtectHome = false;
+            RestrictAddressFamilies = [ "AF_PACKET" ];
+          };
+          default = { };
+        };
+
+        package = mkPackageOption pkgs "github-runner" { };
+
+        ephemeral = mkOption {
+          type = types.bool;
+          description = mdDoc ''
+            If enabled, causes the following behavior:
+
+            - Passes the `--ephemeral` flag to the runner configuration script
+            - De-registers and stops the runner with GitHub after it has processed one job
+            - On stop, systemd wipes the runtime directory (this always happens, even without using the ephemeral option)
+            - Restarts the service after its successful exit
+            - On start, wipes the state directory and configures a new runner
+
+            You should only enable this option if `tokenFile` points to a file which contains a
+            personal access token (PAT). If you're using the option with a registration token, restarting the
+            service will fail as soon as the registration token expired.
+
+            Changing this option triggers a new runner registration.
+          '';
+          default = false;
+        };
+
+        user = mkOption {
+          type = types.nullOr types.str;
+          description = mdDoc ''
+            User under which to run the service.
+
+            If this option and the `group` option is set to `null`,
+            the service runs as a dynamically allocated user.
+
+            Also see the `group` option for an overview on the effects of the `user` and `group` settings.
+          '';
+          default = null;
+          defaultText = literalExpression "username";
+        };
+
+        group = mkOption {
+          type = types.nullOr types.str;
+          description = mdDoc ''
+            Group under which to run the service.
+
+            The effect of this option depends on the value of the `user` option:
+
+            - `group == null` and `user == null`:
+              The service runs with a dynamically allocated user and group.
+            - `group == null` and `user != null`:
+              The service runs as the given user and its default group.
+            - `group != null` and `user == null`:
+              This configuration is invalid. In this case, the service would use the given group
+              but run as root implicitly. If this is really what you want, set `user = "root"` explicitly.
+          '';
+          default = null;
+          defaultText = literalExpression "groupname";
+        };
+
+        workDir = mkOption {
+          type = with types; nullOr str;
+          description = mdDoc ''
+            Working directory, available as `$GITHUB_WORKSPACE` during workflow runs
+            and used as a default for [repository checkouts](https://github.com/actions/checkout).
+            The service cleans this directory on every service start.
+
+            A value of `null` will default to the systemd `RuntimeDirectory`.
+
+            Changing this option triggers a new runner registration.
+          '';
+          default = null;
+        };
+
+        nodeRuntimes = mkOption {
+          type = with types; nonEmptyListOf (enum [ "node20" ]);
+          default = [ "node20" ];
+          description = mdDoc ''
+            List of Node.js runtimes the runner should support.
+          '';
+        };
+      };
+    }));
   };
 }
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/github-runner/service.nix b/nixpkgs/nixos/modules/services/continuous-integration/github-runner/service.nix
index 535df7f68e07..fccdcc116a21 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/github-runner/service.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/github-runner/service.nix
@@ -1,268 +1,299 @@
 { config
 , lib
 , pkgs
-
-, cfg ? config.services.github-runner
-, svcName
-
-, systemdDir ? "${svcName}/${cfg.name}"
-  # %t: Runtime directory root (usually /run); see systemd.unit(5)
-, runtimeDir ? "%t/${systemdDir}"
-  # %S: State directory root (usually /var/lib); see systemd.unit(5)
-, stateDir ? "%S/${systemdDir}"
-  # %L: Log directory root (usually /var/log); see systemd.unit(5)
-, logsDir ? "%L/${systemdDir}"
-  # Name of file stored in service state directory
-, currentConfigTokenFilename ? ".current-token"
-
 , ...
 }:
 
 with lib;
-
-let
-  workDir = if cfg.workDir == null then runtimeDir else cfg.workDir;
-  package = cfg.package.override { inherit (cfg) nodeRuntimes; };
-in
 {
-  description = "GitHub Actions runner";
+  config.assertions = flatten (
+    flip mapAttrsToList config.services.github-runners (name: cfg: map (mkIf cfg.enable) [
+      {
+        assertion = !cfg.noDefaultLabels || (cfg.extraLabels != [ ]);
+        message = "`services.github-runners.${name}`: The `extraLabels` option is mandatory if `noDefaultLabels` is set";
+      }
+      {
+        assertion = cfg.group == null || cfg.user != null;
+        message = ''`services.github-runners.${name}`: Setting `group` while leaving `user` unset runs the service as `root`. If this is really what you want, set `user = "root"` explicitly'';
+      }
+    ])
+  );
 
-  wantedBy = [ "multi-user.target" ];
-  wants = [ "network-online.target" ];
-  after = [ "network.target" "network-online.target" ];
+  config.systemd.services = flip mapAttrs' config.services.github-runners (name: cfg:
+    let
+      svcName = "github-runner-${name}";
+      systemdDir = "github-runner/${name}";
 
-  environment = {
-    HOME = workDir;
-    RUNNER_ROOT = stateDir;
-  } // cfg.extraEnvironment;
+      # %t: Runtime directory root (usually /run); see systemd.unit(5)
+      runtimeDir = "%t/${systemdDir}";
+      # %S: State directory root (usually /var/lib); see systemd.unit(5)
+      stateDir = "%S/${systemdDir}";
+      # %L: Log directory root (usually /var/log); see systemd.unit(5)
+      logsDir = "%L/${systemdDir}";
+      # Name of file stored in service state directory
+      currentConfigTokenFilename = ".current-token";
 
-  path = (with pkgs; [
-    bash
-    coreutils
-    git
-    gnutar
-    gzip
-  ]) ++ [
-    config.nix.package
-  ] ++ cfg.extraPackages;
+      workDir = if cfg.workDir == null then runtimeDir else cfg.workDir;
+      # Support old github-runner versions which don't have the `nodeRuntimes` arg yet.
+      package = cfg.package.override (old: optionalAttrs (hasAttr "nodeRuntimes" old) { inherit (cfg) nodeRuntimes; });
+    in
+    nameValuePair svcName {
+      description = "GitHub Actions runner";
 
-  serviceConfig = mkMerge [
-    {
-      ExecStart = "${package}/bin/Runner.Listener run --startuptype service";
+      wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
+      after = [ "network.target" "network-online.target" ];
 
-      # Does the following, sequentially:
-      # - If the module configuration or the token has changed, purge the state directory,
-      #   and create the current and the new token file with the contents of the configured
-      #   token. While both files have the same content, only the later is accessible by
-      #   the service user.
-      # - Configure the runner using the new token file. When finished, delete it.
-      # - Set up the directory structure by creating the necessary symlinks.
-      ExecStartPre =
-        let
-          # Wrapper script which expects the full path of the state, working and logs
-          # directory as arguments. Overrides the respective systemd variables to provide
-          # unambiguous directory names. This becomes relevant, for example, if the
-          # caller overrides any of the StateDirectory=, RuntimeDirectory= or LogDirectory=
-          # to contain more than one directory. This causes systemd to set the respective
-          # environment variables with the path of all of the given directories, separated
-          # by a colon.
-          writeScript = name: lines: pkgs.writeShellScript "${svcName}-${name}.sh" ''
-            set -euo pipefail
+      environment = {
+        HOME = workDir;
+        RUNNER_ROOT = stateDir;
+      } // cfg.extraEnvironment;
 
-            STATE_DIRECTORY="$1"
-            WORK_DIRECTORY="$2"
-            LOGS_DIRECTORY="$3"
+      path = (with pkgs; [
+        bash
+        coreutils
+        git
+        gnutar
+        gzip
+      ]) ++ [
+        config.nix.package
+      ] ++ cfg.extraPackages;
 
-            ${lines}
-          '';
-          runnerRegistrationConfig = getAttrs [ "name" "tokenFile" "url" "runnerGroup" "extraLabels" "ephemeral" "workDir" ] cfg;
-          newConfigPath = builtins.toFile "${svcName}-config.json" (builtins.toJSON runnerRegistrationConfig);
-          currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json";
-          newConfigTokenPath = "$STATE_DIRECTORY/.new-token";
-          currentConfigTokenPath = "$STATE_DIRECTORY/${currentConfigTokenFilename}";
+      serviceConfig = mkMerge [
+        {
+          ExecStart = "${package}/bin/Runner.Listener run --startuptype service";
 
-          runnerCredFiles = [
-            ".credentials"
-            ".credentials_rsaparams"
-            ".runner"
-          ];
-          unconfigureRunner = writeScript "unconfigure" ''
-            copy_tokens() {
-              # Copy the configured token file to the state dir and allow the service user to read the file
-              install --mode=666 ${escapeShellArg cfg.tokenFile} "${newConfigTokenPath}"
-              # Also copy current file to allow for a diff on the next start
-              install --mode=600 ${escapeShellArg cfg.tokenFile} "${currentConfigTokenPath}"
-            }
-            clean_state() {
-              find "$STATE_DIRECTORY/" -mindepth 1 -delete
-              copy_tokens
-            }
-            diff_config() {
-              changed=0
-              # Check for module config changes
-              [[ -f "${currentConfigPath}" ]] \
-                && ${pkgs.diffutils}/bin/diff -q '${newConfigPath}' "${currentConfigPath}" >/dev/null 2>&1 \
-                || changed=1
-              # Also check the content of the token file
-              [[ -f "${currentConfigTokenPath}" ]] \
-                && ${pkgs.diffutils}/bin/diff -q "${currentConfigTokenPath}" ${escapeShellArg cfg.tokenFile} >/dev/null 2>&1 \
-                || changed=1
-              # If the config has changed, remove old state and copy tokens
-              if [[ "$changed" -eq 1 ]]; then
-                echo "Config has changed, removing old runner state."
-                echo "The old runner will still appear in the GitHub Actions UI." \
-                     "You have to remove it manually."
-                clean_state
-              fi
-            }
-            if [[ "${optionalString cfg.ephemeral "1"}" ]]; then
-              # In ephemeral mode, we always want to start with a clean state
-              clean_state
-            elif [[ "$(ls -A "$STATE_DIRECTORY")" ]]; then
-              # There are state files from a previous run; diff them to decide if we need a new registration
-              diff_config
-            else
-              # The state directory is entirely empty which indicates a first start
-              copy_tokens
-            fi
-            # Always clean workDir
-            find -H "$WORK_DIRECTORY" -mindepth 1 -delete
-          '';
-          configureRunner = writeScript "configure" ''
-            if [[ -e "${newConfigTokenPath}" ]]; then
-              echo "Configuring GitHub Actions Runner"
-              args=(
-                --unattended
-                --disableupdate
-                --work "$WORK_DIRECTORY"
-                --url ${escapeShellArg cfg.url}
-                --labels ${escapeShellArg (concatStringsSep "," cfg.extraLabels)}
-                --name ${escapeShellArg cfg.name}
-                ${optionalString cfg.replace "--replace"}
-                ${optionalString (cfg.runnerGroup != null) "--runnergroup ${escapeShellArg cfg.runnerGroup}"}
-                ${optionalString cfg.ephemeral "--ephemeral"}
-              )
-              # If the token file contains a PAT (i.e., it starts with "ghp_" or "github_pat_"), we have to use the --pat option,
-              # if it is not a PAT, we assume it contains a registration token and use the --token option
-              token=$(<"${newConfigTokenPath}")
-              if [[ "$token" =~ ^ghp_* ]] || [[ "$token" =~ ^github_pat_* ]]; then
-                args+=(--pat "$token")
-              else
-                args+=(--token "$token")
-              fi
-              ${package}/bin/Runner.Listener configure "''${args[@]}"
-              # Move the automatically created _diag dir to the logs dir
-              mkdir -p  "$STATE_DIRECTORY/_diag"
-              cp    -r  "$STATE_DIRECTORY/_diag/." "$LOGS_DIRECTORY/"
-              rm    -rf "$STATE_DIRECTORY/_diag/"
-              # Cleanup token from config
-              rm "${newConfigTokenPath}"
-              # Symlink to new config
-              ln -s '${newConfigPath}' "${currentConfigPath}"
-            fi
-          '';
-          setupWorkDir = writeScript "setup-work-dirs" ''
-            # Link _diag dir
-            ln -s "$LOGS_DIRECTORY" "$WORK_DIRECTORY/_diag"
+          # Does the following, sequentially:
+          # - If the module configuration or the token has changed, purge the state directory,
+          #   and create the current and the new token file with the contents of the configured
+          #   token. While both files have the same content, only the later is accessible by
+          #   the service user.
+          # - Configure the runner using the new token file. When finished, delete it.
+          # - Set up the directory structure by creating the necessary symlinks.
+          ExecStartPre =
+            let
+              # Wrapper script which expects the full path of the state, working and logs
+              # directory as arguments. Overrides the respective systemd variables to provide
+              # unambiguous directory names. This becomes relevant, for example, if the
+              # caller overrides any of the StateDirectory=, RuntimeDirectory= or LogDirectory=
+              # to contain more than one directory. This causes systemd to set the respective
+              # environment variables with the path of all of the given directories, separated
+              # by a colon.
+              writeScript = name: lines: pkgs.writeShellScript "${svcName}-${name}.sh" ''
+                set -euo pipefail
 
-            # Link the runner credentials to the work dir
-            ln -s "$STATE_DIRECTORY"/{${lib.concatStringsSep "," runnerCredFiles}} "$WORK_DIRECTORY/"
-          '';
-        in
-        map (x: "${x} ${escapeShellArgs [ stateDir workDir logsDir ]}") [
-          "+${unconfigureRunner}" # runs as root
-          configureRunner
-          setupWorkDir
-        ];
+                STATE_DIRECTORY="$1"
+                WORK_DIRECTORY="$2"
+                LOGS_DIRECTORY="$3"
 
-      # If running in ephemeral mode, restart the service on-exit (i.e., successful de-registration of the runner)
-      # to trigger a fresh registration.
-      Restart = if cfg.ephemeral then "on-success" else "no";
-      # If the runner exits with `ReturnCode.RetryableError = 2`, always restart the service:
-      # https://github.com/actions/runner/blob/40ed7f8/src/Runner.Common/Constants.cs#L146
-      RestartForceExitStatus = [ 2 ];
+                ${lines}
+              '';
+              runnerRegistrationConfig = getAttrs [
+                "ephemeral"
+                "extraLabels"
+                "name"
+                "noDefaultLabels"
+                "runnerGroup"
+                "tokenFile"
+                "url"
+                "workDir"
+              ]
+                cfg;
+              newConfigPath = builtins.toFile "${svcName}-config.json" (builtins.toJSON runnerRegistrationConfig);
+              currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json";
+              newConfigTokenPath = "$STATE_DIRECTORY/.new-token";
+              currentConfigTokenPath = "$STATE_DIRECTORY/${currentConfigTokenFilename}";
 
-      # Contains _diag
-      LogsDirectory = [ systemdDir ];
-      # Default RUNNER_ROOT which contains ephemeral Runner data
-      RuntimeDirectory = [ systemdDir ];
-      # Home of persistent runner data, e.g., credentials
-      StateDirectory = [ systemdDir ];
-      StateDirectoryMode = "0700";
-      WorkingDirectory = workDir;
+              runnerCredFiles = [
+                ".credentials"
+                ".credentials_rsaparams"
+                ".runner"
+              ];
+              unconfigureRunner = writeScript "unconfigure" ''
+                copy_tokens() {
+                  # Copy the configured token file to the state dir and allow the service user to read the file
+                  install --mode=666 ${escapeShellArg cfg.tokenFile} "${newConfigTokenPath}"
+                  # Also copy current file to allow for a diff on the next start
+                  install --mode=600 ${escapeShellArg cfg.tokenFile} "${currentConfigTokenPath}"
+                }
+                clean_state() {
+                  find "$STATE_DIRECTORY/" -mindepth 1 -delete
+                  copy_tokens
+                }
+                diff_config() {
+                  changed=0
+                  # Check for module config changes
+                  [[ -f "${currentConfigPath}" ]] \
+                    && ${pkgs.diffutils}/bin/diff -q '${newConfigPath}' "${currentConfigPath}" >/dev/null 2>&1 \
+                    || changed=1
+                  # Also check the content of the token file
+                  [[ -f "${currentConfigTokenPath}" ]] \
+                    && ${pkgs.diffutils}/bin/diff -q "${currentConfigTokenPath}" ${escapeShellArg cfg.tokenFile} >/dev/null 2>&1 \
+                    || changed=1
+                  # If the config has changed, remove old state and copy tokens
+                  if [[ "$changed" -eq 1 ]]; then
+                    echo "Config has changed, removing old runner state."
+                    echo "The old runner will still appear in the GitHub Actions UI." \
+                         "You have to remove it manually."
+                    clean_state
+                  fi
+                }
+                if [[ "${optionalString cfg.ephemeral "1"}" ]]; then
+                  # In ephemeral mode, we always want to start with a clean state
+                  clean_state
+                elif [[ "$(ls -A "$STATE_DIRECTORY")" ]]; then
+                  # There are state files from a previous run; diff them to decide if we need a new registration
+                  diff_config
+                else
+                  # The state directory is entirely empty which indicates a first start
+                  copy_tokens
+                fi
+                # Always clean workDir
+                find -H "$WORK_DIRECTORY" -mindepth 1 -delete
+              '';
+              configureRunner = writeScript "configure" ''
+                if [[ -e "${newConfigTokenPath}" ]]; then
+                  echo "Configuring GitHub Actions Runner"
+                  args=(
+                    --unattended
+                    --disableupdate
+                    --work "$WORK_DIRECTORY"
+                    --url ${escapeShellArg cfg.url}
+                    --labels ${escapeShellArg (concatStringsSep "," cfg.extraLabels)}
+                    ${optionalString (cfg.name != null ) "--name ${escapeShellArg cfg.name}"}
+                    ${optionalString cfg.replace "--replace"}
+                    ${optionalString (cfg.runnerGroup != null) "--runnergroup ${escapeShellArg cfg.runnerGroup}"}
+                    ${optionalString cfg.ephemeral "--ephemeral"}
+                    ${optionalString cfg.noDefaultLabels "--no-default-labels"}
+                  )
+                  # If the token file contains a PAT (i.e., it starts with "ghp_" or "github_pat_"), we have to use the --pat option,
+                  # if it is not a PAT, we assume it contains a registration token and use the --token option
+                  token=$(<"${newConfigTokenPath}")
+                  if [[ "$token" =~ ^ghp_* ]] || [[ "$token" =~ ^github_pat_* ]]; then
+                    args+=(--pat "$token")
+                  else
+                    args+=(--token "$token")
+                  fi
+                  ${package}/bin/Runner.Listener configure "''${args[@]}"
+                  # Move the automatically created _diag dir to the logs dir
+                  mkdir -p  "$STATE_DIRECTORY/_diag"
+                  cp    -r  "$STATE_DIRECTORY/_diag/." "$LOGS_DIRECTORY/"
+                  rm    -rf "$STATE_DIRECTORY/_diag/"
+                  # Cleanup token from config
+                  rm "${newConfigTokenPath}"
+                  # Symlink to new config
+                  ln -s '${newConfigPath}' "${currentConfigPath}"
+                fi
+              '';
+              setupWorkDir = writeScript "setup-work-dirs" ''
+                # Link _diag dir
+                ln -s "$LOGS_DIRECTORY" "$WORK_DIRECTORY/_diag"
 
-      InaccessiblePaths = [
-        # Token file path given in the configuration, if visible to the service
-        "-${cfg.tokenFile}"
-        # Token file in the state directory
-        "${stateDir}/${currentConfigTokenFilename}"
-      ];
+                # Link the runner credentials to the work dir
+                ln -s "$STATE_DIRECTORY"/{${lib.concatStringsSep "," runnerCredFiles}} "$WORK_DIRECTORY/"
+              '';
+            in
+            map (x: "${x} ${escapeShellArgs [ stateDir workDir logsDir ]}") [
+              "+${unconfigureRunner}" # runs as root
+              configureRunner
+              setupWorkDir
+            ];
 
-      KillSignal = "SIGINT";
+          # If running in ephemeral mode, restart the service on-exit (i.e., successful de-registration of the runner)
+          # to trigger a fresh registration.
+          Restart = if cfg.ephemeral then "on-success" else "no";
+          # If the runner exits with `ReturnCode.RetryableError = 2`, always restart the service:
+          # https://github.com/actions/runner/blob/40ed7f8/src/Runner.Common/Constants.cs#L146
+          RestartForceExitStatus = [ 2 ];
 
-      # Hardening (may overlap with DynamicUser=)
-      # The following options are only for optimizing:
-      # systemd-analyze security github-runner
-      AmbientCapabilities = mkBefore [ "" ];
-      CapabilityBoundingSet = mkBefore [ "" ];
-      # ProtectClock= adds DeviceAllow=char-rtc r
-      DeviceAllow = mkBefore [ "" ];
-      NoNewPrivileges = mkDefault true;
-      PrivateDevices = mkDefault true;
-      PrivateMounts = mkDefault true;
-      PrivateTmp = mkDefault true;
-      PrivateUsers = mkDefault true;
-      ProtectClock = mkDefault true;
-      ProtectControlGroups = mkDefault true;
-      ProtectHome = mkDefault true;
-      ProtectHostname = mkDefault true;
-      ProtectKernelLogs = mkDefault true;
-      ProtectKernelModules = mkDefault true;
-      ProtectKernelTunables = mkDefault true;
-      ProtectSystem = mkDefault "strict";
-      RemoveIPC = mkDefault true;
-      RestrictNamespaces = mkDefault true;
-      RestrictRealtime = mkDefault true;
-      RestrictSUIDSGID = mkDefault true;
-      UMask = mkDefault "0066";
-      ProtectProc = mkDefault "invisible";
-      SystemCallFilter = mkBefore [
-        "~@clock"
-        "~@cpu-emulation"
-        "~@module"
-        "~@mount"
-        "~@obsolete"
-        "~@raw-io"
-        "~@reboot"
-        "~capset"
-        "~setdomainname"
-        "~sethostname"
-      ];
-      RestrictAddressFamilies = mkBefore [ "AF_INET" "AF_INET6" "AF_UNIX" "AF_NETLINK" ];
+          # Contains _diag
+          LogsDirectory = [ systemdDir ];
+          # Default RUNNER_ROOT which contains ephemeral Runner data
+          RuntimeDirectory = [ systemdDir ];
+          # Home of persistent runner data, e.g., credentials
+          StateDirectory = [ systemdDir ];
+          StateDirectoryMode = "0700";
+          WorkingDirectory = workDir;
 
-      BindPaths = lib.optionals (cfg.workDir != null) [ cfg.workDir ];
+          InaccessiblePaths = [
+            # Token file path given in the configuration, if visible to the service
+            "-${cfg.tokenFile}"
+            # Token file in the state directory
+            "${stateDir}/${currentConfigTokenFilename}"
+          ];
+
+          KillSignal = "SIGINT";
+
+          # Hardening (may overlap with DynamicUser=)
+          # The following options are only for optimizing:
+          # systemd-analyze security github-runner
+          AmbientCapabilities = mkBefore [ "" ];
+          CapabilityBoundingSet = mkBefore [ "" ];
+          # ProtectClock= adds DeviceAllow=char-rtc r
+          DeviceAllow = mkBefore [ "" ];
+          NoNewPrivileges = mkDefault true;
+          PrivateDevices = mkDefault true;
+          PrivateMounts = mkDefault true;
+          PrivateTmp = mkDefault true;
+          PrivateUsers = mkDefault true;
+          ProtectClock = mkDefault true;
+          ProtectControlGroups = mkDefault true;
+          ProtectHome = mkDefault true;
+          ProtectHostname = mkDefault true;
+          ProtectKernelLogs = mkDefault true;
+          ProtectKernelModules = mkDefault true;
+          ProtectKernelTunables = mkDefault true;
+          ProtectSystem = mkDefault "strict";
+          RemoveIPC = mkDefault true;
+          RestrictNamespaces = mkDefault true;
+          RestrictRealtime = mkDefault true;
+          RestrictSUIDSGID = mkDefault true;
+          UMask = mkDefault "0066";
+          ProtectProc = mkDefault "invisible";
+          SystemCallFilter = mkBefore [
+            "~@clock"
+            "~@cpu-emulation"
+            "~@module"
+            "~@mount"
+            "~@obsolete"
+            "~@raw-io"
+            "~@reboot"
+            "~capset"
+            "~setdomainname"
+            "~sethostname"
+          ];
+          RestrictAddressFamilies = mkBefore [ "AF_INET" "AF_INET6" "AF_UNIX" "AF_NETLINK" ];
+
+          BindPaths = lib.optionals (cfg.workDir != null) [ cfg.workDir ];
 
-      # Needs network access
-      PrivateNetwork = mkDefault false;
-      # Cannot be true due to Node
-      MemoryDenyWriteExecute = mkDefault false;
+          # Needs network access
+          PrivateNetwork = mkDefault false;
+          # Cannot be true due to Node
+          MemoryDenyWriteExecute = mkDefault false;
 
-      # The more restrictive "pid" option makes `nix` commands in CI emit
-      # "GC Warning: Couldn't read /proc/stat"
-      # You may want to set this to "pid" if not using `nix` commands
-      ProcSubset = mkDefault "all";
-      # Coverage programs for compiled code such as `cargo-tarpaulin` disable
-      # ASLR (address space layout randomization) which requires the
-      # `personality` syscall
-      # You may want to set this to `true` if not using coverage tooling on
-      # compiled code
-      LockPersonality = mkDefault false;
+          # The more restrictive "pid" option makes `nix` commands in CI emit
+          # "GC Warning: Couldn't read /proc/stat"
+          # You may want to set this to "pid" if not using `nix` commands
+          ProcSubset = mkDefault "all";
+          # Coverage programs for compiled code such as `cargo-tarpaulin` disable
+          # ASLR (address space layout randomization) which requires the
+          # `personality` syscall
+          # You may want to set this to `true` if not using coverage tooling on
+          # compiled code
+          LockPersonality = mkDefault false;
 
-      # Note that this has some interactions with the User setting; so you may
-      # want to consult the systemd docs if using both.
-      DynamicUser = mkDefault true;
+          DynamicUser = mkDefault true;
+        }
+        (mkIf (cfg.user != null) {
+          DynamicUser = false;
+          User = cfg.user;
+        })
+        (mkIf (cfg.group != null) {
+          DynamicUser = false;
+          Group = cfg.group;
+        })
+        cfg.serviceOverrides
+      ];
     }
-    (mkIf (cfg.user != null) { User = cfg.user; })
-    cfg.serviceOverrides
-  ];
+  );
 }
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/github-runners.nix b/nixpkgs/nixos/modules/services/continuous-integration/github-runners.nix
index 66ace9580eca..4a4608c2e4f8 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/github-runners.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/github-runners.nix
@@ -1,58 +1,10 @@
-{ config
-, pkgs
-, lib
-, ...
-}@args:
-
-with lib;
-
-let
-  cfg = config.services.github-runners;
-
-in
-
+{ lib, ... }:
 {
-  options.services.github-runners = mkOption {
-    default = {};
-    type = with types; attrsOf (submodule { options = import ./github-runner/options.nix (args // {
-      # services.github-runners.${name}.name doesn't have a default; it falls back to ${name} below.
-      includeNameDefault = false;
-    }); });
-    example = {
-      runner1 = {
-        enable = true;
-        url = "https://github.com/owner/repo";
-        name = "runner1";
-        tokenFile = "/secrets/token1";
-      };
-
-      runner2 = {
-        enable = true;
-        url = "https://github.com/owner/repo";
-        name = "runner2";
-        tokenFile = "/secrets/token2";
-      };
-    };
-    description = lib.mdDoc ''
-      Multiple GitHub Runners.
-    '';
-  };
-
-  config = {
-    systemd.services = flip mapAttrs' cfg (n: v:
-      let
-        svcName = "github-runner-${n}";
-      in
-        nameValuePair svcName
-        (import ./github-runner/service.nix (args // {
-          inherit svcName;
-          cfg = v // {
-            name = if v.name != null then v.name else n;
-          };
-          systemdDir = "github-runner/${n}";
-        }))
-    );
-  };
+  imports = [
+    (lib.mkRemovedOptionModule [ "services" "github-runner" ] "Use `services.github-runners.*` instead")
+    ./github-runner/options.nix
+    ./github-runner/service.nix
+  ];
 
-  meta.maintainers = with maintainers; [ veehaitch newam ];
+  meta.maintainers = with lib.maintainers; [ veehaitch newam ];
 }
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix b/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix
index 46b03bba37be..54bbe69703f9 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -393,6 +393,7 @@ in
     systemd.services.hydra-evaluator =
       { wantedBy = [ "multi-user.target" ];
         requires = [ "hydra-init.service" ];
+        wants = [ "network-online.target" ];
         after = [ "hydra-init.service" "network.target" "network-online.target" ];
         path = with pkgs; [ hydra-package nettools jq ];
         restartTriggers = [ hydraConf ];
diff --git a/nixpkgs/nixos/modules/services/misc/etcd.nix b/nixpkgs/nixos/modules/services/databases/etcd.nix
index 73bdeb3b0afd..a5b3abdbcb59 100644
--- a/nixpkgs/nixos/modules/services/misc/etcd.nix
+++ b/nixpkgs/nixos/modules/services/databases/etcd.nix
@@ -99,6 +99,17 @@ in {
       type = types.nullOr types.path;
     };
 
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = lib.mdDoc ''
+        Open etcd ports in the firewall.
+        Ports opened:
+        - 2379/tcp for client requests
+        - 2380/tcp for peer communication
+      '';
+    };
+
     peerCertFile = mkOption {
       description = lib.mdDoc "Cert file to use for peer to peer communication";
       default = cfg.certFile;
@@ -152,14 +163,18 @@ in {
   };
 
   config = mkIf cfg.enable {
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' 0700 etcd - - -"
-    ];
+    systemd.tmpfiles.settings."10-etcd".${cfg.dataDir}.d = {
+      user = "etcd";
+      mode = "0700";
+    };
 
     systemd.services.etcd = {
       description = "etcd key-value store";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
+      after = [ "network-online.target" ]
+        ++ lib.optional config.networking.firewall.enable "firewall.service";
+      wants = [ "network-online.target" ]
+        ++ lib.optional config.networking.firewall.enable "firewall.service";
 
       environment = (filterAttrs (n: v: v != null) {
         ETCD_NAME = cfg.name;
@@ -189,6 +204,8 @@ in {
 
       serviceConfig = {
         Type = "notify";
+        Restart = "always";
+        RestartSec = "30s";
         ExecStart = "${cfg.package}/bin/etcd";
         User = "etcd";
         LimitNOFILE = 40000;
@@ -197,6 +214,13 @@ in {
 
     environment.systemPackages = [ cfg.package ];
 
+    networking.firewall = lib.mkIf cfg.openFirewall {
+      allowedTCPPorts = [
+        2379 # for client requests
+        2380 # for peer communication
+      ];
+    };
+
     users.users.etcd = {
       isSystemUser = true;
       group = "etcd";
diff --git a/nixpkgs/nixos/modules/services/databases/firebird.nix b/nixpkgs/nixos/modules/services/databases/firebird.nix
index 36c12eaaf5f1..431233ce5ed4 100644
--- a/nixpkgs/nixos/modules/services/databases/firebird.nix
+++ b/nixpkgs/nixos/modules/services/databases/firebird.nix
@@ -143,7 +143,7 @@ in
       # ConnectionTimeout = 180
 
       #RemoteServiceName = gds_db
-      RemoteServicePort = ${cfg.port}
+      RemoteServicePort = ${toString cfg.port}
 
       # randomly choose port for server Event Notification
       #RemoteAuxPort = 0
diff --git a/nixpkgs/nixos/modules/services/databases/lldap.nix b/nixpkgs/nixos/modules/services/databases/lldap.nix
index d1574c98fe67..e821da8e58aa 100644
--- a/nixpkgs/nixos/modules/services/databases/lldap.nix
+++ b/nixpkgs/nixos/modules/services/databases/lldap.nix
@@ -104,6 +104,7 @@ in
   config = lib.mkIf cfg.enable {
     systemd.services.lldap = {
       description = "Lightweight LDAP server (lldap)";
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/databases/neo4j.nix b/nixpkgs/nixos/modules/services/databases/neo4j.nix
index 56b916ee3758..45630e2d4488 100644
--- a/nixpkgs/nixos/modules/services/databases/neo4j.nix
+++ b/nixpkgs/nixos/modules/services/databases/neo4j.nix
@@ -35,65 +35,64 @@ let
 
   serverConfig = pkgs.writeText "neo4j.conf" ''
     # General
-    dbms.allow_upgrade=${boolToString cfg.allowUpgrade}
-    dbms.default_listen_address=${cfg.defaultListenAddress}
-    dbms.databases.default_to_read_only=${boolToString cfg.readOnly}
+    server.default_listen_address=${cfg.defaultListenAddress}
+    server.databases.default_to_read_only=${boolToString cfg.readOnly}
     ${optionalString (cfg.workerCount > 0) ''
       dbms.threads.worker_count=${toString cfg.workerCount}
     ''}
 
     # Directories (readonly)
-    dbms.directories.certificates=${cfg.directories.certificates}
-    dbms.directories.plugins=${cfg.directories.plugins}
-    dbms.directories.lib=${cfg.package}/share/neo4j/lib
+    # dbms.directories.certificates=${cfg.directories.certificates}
+    server.directories.plugins=${cfg.directories.plugins}
+    server.directories.lib=${cfg.package}/share/neo4j/lib
     ${optionalString (cfg.constrainLoadCsv) ''
-      dbms.directories.import=${cfg.directories.imports}
+      server.directories.import=${cfg.directories.imports}
    ''}
 
     # Directories (read and write)
-    dbms.directories.data=${cfg.directories.data}
-    dbms.directories.logs=${cfg.directories.home}/logs
-    dbms.directories.run=${cfg.directories.home}/run
+    server.directories.data=${cfg.directories.data}
+    server.directories.logs=${cfg.directories.home}/logs
+    server.directories.run=${cfg.directories.home}/run
 
     # HTTP Connector
     ${optionalString (cfg.http.enable) ''
-      dbms.connector.http.enabled=${boolToString cfg.http.enable}
-      dbms.connector.http.listen_address=${cfg.http.listenAddress}
-      dbms.connector.http.advertised_address=${cfg.http.listenAddress}
+      server.http.enabled=${boolToString cfg.http.enable}
+      server.http.listen_address=${cfg.http.listenAddress}
+      server.http.advertised_address=${cfg.http.listenAddress}
     ''}
 
     # HTTPS Connector
-    dbms.connector.https.enabled=${boolToString cfg.https.enable}
-    dbms.connector.https.listen_address=${cfg.https.listenAddress}
-    dbms.connector.https.advertised_address=${cfg.https.listenAddress}
+    server.https.enabled=${boolToString cfg.https.enable}
+    server.https.listen_address=${cfg.https.listenAddress}
+    server.https.advertised_address=${cfg.https.listenAddress}
 
     # BOLT Connector
-    dbms.connector.bolt.enabled=${boolToString cfg.bolt.enable}
-    dbms.connector.bolt.listen_address=${cfg.bolt.listenAddress}
-    dbms.connector.bolt.advertised_address=${cfg.bolt.listenAddress}
-    dbms.connector.bolt.tls_level=${cfg.bolt.tlsLevel}
+    server.bolt.enabled=${boolToString cfg.bolt.enable}
+    server.bolt.listen_address=${cfg.bolt.listenAddress}
+    server.bolt.advertised_address=${cfg.bolt.listenAddress}
+    server.bolt.tls_level=${cfg.bolt.tlsLevel}
 
     # SSL Policies
     ${concatStringsSep "\n" sslPolicies}
 
     # Default retention policy from neo4j.conf
-    dbms.tx_log.rotation.retention_policy=1 days
+    db.tx_log.rotation.retention_policy=1 days
 
     # Default JVM parameters from neo4j.conf
-    dbms.jvm.additional=-XX:+UseG1GC
-    dbms.jvm.additional=-XX:-OmitStackTraceInFastThrow
-    dbms.jvm.additional=-XX:+AlwaysPreTouch
-    dbms.jvm.additional=-XX:+UnlockExperimentalVMOptions
-    dbms.jvm.additional=-XX:+TrustFinalNonStaticFields
-    dbms.jvm.additional=-XX:+DisableExplicitGC
-    dbms.jvm.additional=-Djdk.tls.ephemeralDHKeySize=2048
-    dbms.jvm.additional=-Djdk.tls.rejectClientInitiatedRenegotiation=true
-    dbms.jvm.additional=-Dunsupported.dbms.udc.source=tarball
-
-    #dbms.memory.heap.initial_size=12000m
-    #dbms.memory.heap.max_size=12000m
-    #dbms.memory.pagecache.size=4g
-    #dbms.tx_state.max_off_heap_memory=8000m
+    server.jvm.additional=-XX:+UseG1GC
+    server.jvm.additional=-XX:-OmitStackTraceInFastThrow
+    server.jvm.additional=-XX:+AlwaysPreTouch
+    server.jvm.additional=-XX:+UnlockExperimentalVMOptions
+    server.jvm.additional=-XX:+TrustFinalNonStaticFields
+    server.jvm.additional=-XX:+DisableExplicitGC
+    server.jvm.additional=-Djdk.tls.ephemeralDHKeySize=2048
+    server.jvm.additional=-Djdk.tls.rejectClientInitiatedRenegotiation=true
+    server.jvm.additional=-Dunsupported.dbms.udc.source=tarball
+
+    #server.memory.off_heap.transaction_max_size=12000m
+    #server.memory.heap.max_size=12000m
+    #server.memory.pagecache.size=4g
+    #server.tx_state.max_off_heap_memory=8000m
 
     # Extra Configuration
     ${cfg.extraServerConfig}
@@ -127,14 +126,6 @@ in {
       '';
     };
 
-    allowUpgrade = mkOption {
-      type = types.bool;
-      default = false;
-      description = lib.mdDoc ''
-        Allow upgrade of Neo4j database files from an older version.
-      '';
-    };
-
     constrainLoadCsv = mkOption {
       type = types.bool;
       default = true;
diff --git a/nixpkgs/nixos/modules/services/databases/openldap.nix b/nixpkgs/nixos/modules/services/databases/openldap.nix
index a7a0909f55e1..df36e37976a4 100644
--- a/nixpkgs/nixos/modules/services/databases/openldap.nix
+++ b/nixpkgs/nixos/modules/services/databases/openldap.nix
@@ -294,6 +294,7 @@ in {
         "man:slapd-mdb"
       ];
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       serviceConfig = {
         User = cfg.user;
diff --git a/nixpkgs/nixos/modules/services/databases/tigerbeetle.md b/nixpkgs/nixos/modules/services/databases/tigerbeetle.md
new file mode 100644
index 000000000000..47394d443059
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/databases/tigerbeetle.md
@@ -0,0 +1,33 @@
+# TigerBeetle {#module-services-tigerbeetle}
+
+*Source:* {file}`modules/services/databases/tigerbeetle.nix`
+
+*Upstream documentation:* <https://docs.tigerbeetle.com/>
+
+TigerBeetle is a distributed financial accounting database designed for mission critical safety and performance.
+
+To enable TigerBeetle, add the following to your {file}`configuration.nix`:
+```
+  services.tigerbeetle.enable = true;
+```
+
+When first started, the TigerBeetle service will create its data file at {file}`/var/lib/tigerbeetle` unless the file already exists, in which case it will just use the existing file.
+If you make changes to the configuration of TigerBeetle after its data file was already created (for example increasing the replica count), you may need to remove the existing file to avoid conflicts.
+
+## Configuring {#module-services-tigerbeetle-configuring}
+
+By default, TigerBeetle will only listen on a local interface.
+To configure it to listen on a different interface (and to configure it to connect to other replicas, if you're creating more than one), you'll have to set the `addresses` option.
+Note that the TigerBeetle module won't open any firewall ports automatically, so if you configure it to listen on an external interface, you'll need to ensure that connections can reach it:
+
+```
+  services.tigerbeetle = {
+    enable = true;
+    addresses = [ "0.0.0.0:3001" ];
+  };
+
+  networking.firewall.allowedTCPPorts = [ 3001 ];
+```
+
+A complete list of options for TigerBeetle can be found [here](#opt-services.tigerbeetle.enable).
+
diff --git a/nixpkgs/nixos/modules/services/databases/tigerbeetle.nix b/nixpkgs/nixos/modules/services/databases/tigerbeetle.nix
new file mode 100644
index 000000000000..b90a0703175f
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/databases/tigerbeetle.nix
@@ -0,0 +1,115 @@
+{ config, lib, pkgs, ... }:
+let
+  cfg = config.services.tigerbeetle;
+in
+{
+  meta = {
+    maintainers = with lib.maintainers; [ danielsidhion ];
+    doc = ./tigerbeetle.md;
+    buildDocsInSandbox = true;
+  };
+
+  options = {
+    services.tigerbeetle = with lib; {
+      enable = mkEnableOption (mdDoc "TigerBeetle server");
+
+      package = mkPackageOption pkgs "tigerbeetle" { };
+
+      clusterId = mkOption {
+        type = types.either types.ints.unsigned (types.strMatching "[0-9]+");
+        default = 0;
+        description = lib.mdDoc ''
+          The 128-bit cluster ID used to create the replica data file (if needed).
+          Since Nix only supports integers up to 64 bits, you need to pass a string to this if the cluster ID can't fit in 64 bits.
+          Otherwise, you can pass the cluster ID as either an integer or a string.
+        '';
+      };
+
+      replicaIndex = mkOption {
+        type = types.ints.unsigned;
+        default = 0;
+        description = lib.mdDoc ''
+          The index (starting at 0) of the replica in the cluster.
+        '';
+      };
+
+      replicaCount = mkOption {
+        type = types.ints.unsigned;
+        default = 1;
+        description = lib.mdDoc ''
+          The number of replicas participating in replication of the cluster.
+        '';
+      };
+
+      cacheGridSize = mkOption {
+        type = types.strMatching "[0-9]+(K|M|G)B";
+        default = "1GB";
+        description = lib.mdDoc ''
+          The grid cache size.
+          The grid cache acts like a page cache for TigerBeetle.
+          It is recommended to set this as large as possible.
+        '';
+      };
+
+      addresses = mkOption {
+        type = types.listOf types.nonEmptyStr;
+        default = [ "3001" ];
+        description = lib.mdDoc ''
+          The addresses of all replicas in the cluster.
+          This should be a list of IPv4/IPv6 addresses with port numbers.
+          Either the address or port number (but not both) may be omitted, in which case a default of 127.0.0.1 or 3001 will be used.
+          The first address in the list corresponds to the address for replica 0, the second address for replica 1, and so on.
+        '';
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    assertions =
+      let
+        numAddresses = builtins.length cfg.addresses;
+      in
+      [
+        {
+          assertion = cfg.replicaIndex < cfg.replicaCount;
+          message = "the TigerBeetle replica index must fit the configured replica count";
+        }
+        {
+          assertion = cfg.replicaCount == numAddresses;
+          message = if cfg.replicaCount < numAddresses then "TigerBeetle must not have more addresses than the configured number of replicas" else "TigerBeetle must be configured with the addresses of all replicas";
+        }
+      ];
+
+    systemd.services.tigerbeetle =
+      let
+        replicaDataPath = "/var/lib/tigerbeetle/${builtins.toString cfg.clusterId}_${builtins.toString cfg.replicaIndex}.tigerbeetle";
+      in
+      {
+        description = "TigerBeetle server";
+
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
+
+        preStart = ''
+          if ! test -e "${replicaDataPath}"; then
+            ${lib.getExe cfg.package} format --cluster="${builtins.toString cfg.clusterId}" --replica="${builtins.toString cfg.replicaIndex}" --replica-count="${builtins.toString cfg.replicaCount}" "${replicaDataPath}"
+          fi
+        '';
+
+        serviceConfig = {
+          Type = "exec";
+
+          DynamicUser = true;
+          ProtectHome = true;
+          DevicePolicy = "closed";
+
+          StateDirectory = "tigerbeetle";
+          StateDirectoryMode = 700;
+
+          ExecStart = "${lib.getExe cfg.package} start --cache-grid=${cfg.cacheGridSize} --addresses=${lib.escapeShellArg (builtins.concatStringsSep "," cfg.addresses)} ${replicaDataPath}";
+        };
+      };
+
+    environment.systemPackages = [ cfg.package ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/desktops/geoclue2.nix b/nixpkgs/nixos/modules/services/desktops/geoclue2.nix
index b04f46c26a56..2a68bb0b55f3 100644
--- a/nixpkgs/nixos/modules/services/desktops/geoclue2.nix
+++ b/nixpkgs/nixos/modules/services/desktops/geoclue2.nix
@@ -200,6 +200,7 @@ in
     };
 
     systemd.services.geoclue = {
+      wants = lib.optionals cfg.enableWifi [ "network-online.target" ];
       after = lib.optionals cfg.enableWifi [ "network-online.target" ];
       # restart geoclue service when the configuration changes
       restartTriggers = [
@@ -217,6 +218,7 @@ in
         # we can't be part of a system service, and the agent should
         # be okay with the main service coming and going
         wantedBy = [ "default.target" ];
+        wants = lib.optionals cfg.enableWifi [ "network-online.target" ];
         after = lib.optionals cfg.enableWifi [ "network-online.target" ];
         unitConfig.ConditionUser = "!@system";
         serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/development/livebook.md b/nixpkgs/nixos/modules/services/development/livebook.md
index 5012e977a4f7..5315f2c2755a 100644
--- a/nixpkgs/nixos/modules/services/development/livebook.md
+++ b/nixpkgs/nixos/modules/services/development/livebook.md
@@ -15,11 +15,12 @@ which runs the server.
 {
   services.livebook = {
     enableUserService = true;
-    port = 20123;
+    environment = {
+      LIVEBOOK_PORT = 20123;
+      LIVEBOOK_PASSWORD = "mypassword";
+    };
     # See note below about security
-    environmentFile = pkgs.writeText "livebook.env" ''
-      LIVEBOOK_PASSWORD = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
-    '';
+    environmentFile = "/var/lib/livebook.env";
   };
 }
 ```
@@ -30,14 +31,19 @@ The Livebook server has the ability to run any command as the user it
 is running under, so securing access to it with a password is highly
 recommended.
 
-Putting the password in the Nix configuration like above is an easy
-way to get started but it is not recommended in the real world because
-the `livebook.env` file will be added to the world-readable Nix store.
-A better approach would be to put the password in some secure
-user-readable location and set `environmentFile = /home/user/secure/livebook.env`.
+Putting the password in the Nix configuration like above is an easy way to get
+started but it is not recommended in the real world because the resulting
+environment variables can be read by unprivileged users.  A better approach
+would be to put the password in some secure user-readable location and set
+`environmentFile = /home/user/secure/livebook.env`.
 
 :::
 
+The [Livebook
+documentation](https://hexdocs.pm/livebook/readme.html#environment-variables)
+lists all the applicable environment variables. It is recommended to at least
+set `LIVEBOOK_PASSWORD` or `LIVEBOOK_TOKEN_ENABLED=false`.
+
 ### Extra dependencies {#module-services-livebook-extra-dependencies}
 
 By default, the Livebook service is run with minimum dependencies, but
diff --git a/nixpkgs/nixos/modules/services/development/livebook.nix b/nixpkgs/nixos/modules/services/development/livebook.nix
index 75729ff28efa..df0e6e01e97c 100644
--- a/nixpkgs/nixos/modules/services/development/livebook.nix
+++ b/nixpkgs/nixos/modules/services/development/livebook.nix
@@ -14,58 +14,64 @@ in
 
     package = mkPackageOption pkgs "livebook" { };
 
-    environmentFile = mkOption {
-      type = types.path;
+    environment = mkOption {
+      type = with types; attrsOf (nullOr (oneOf [ bool int str ]));
+      default = { };
       description = lib.mdDoc ''
-        Environment file as defined in {manpage}`systemd.exec(5)` passed to the service.
+        Environment variables to set.
 
-        This must contain at least `LIVEBOOK_PASSWORD` or
-        `LIVEBOOK_TOKEN_ENABLED=false`.  See `livebook server --help`
-        for other options.'';
-    };
+        Livebook is configured through the use of environment variables. The
+        available configuration options can be found in the [Livebook
+        documentation](https://hexdocs.pm/livebook/readme.html#environment-variables).
 
-    erlang_node_short_name = mkOption {
-      type = with types; nullOr str;
-      default = null;
-      example = "livebook";
-      description = "A short name for the distributed node.";
-    };
+        Note that all environment variables set through this configuration
+        parameter will be readable by anyone with access to the host
+        machine. Therefore, sensitive information like {env}`LIVEBOOK_PASSWORD`
+        or {env}`LIVEBOOK_COOKIE` should never be set using this configuration
+        option, but should instead use
+        [](#opt-services.livebook.environmentFile). See the documentation for
+        that option for more information.
 
-    erlang_node_name = mkOption {
-      type = with types; nullOr str;
-      default = null;
-      example = "livebook@127.0.0.1";
-      description = "The name for the app distributed node.";
-    };
-
-    port = mkOption {
-      type = types.port;
-      default = 8080;
-      description = "The port to start the web application on.";
-    };
-
-    address = mkOption {
-      type = types.str;
-      default = "127.0.0.1";
-      description = lib.mdDoc ''
-        The address to start the web application on.  Must be a valid IPv4 or
-        IPv6 address.
+        Any environment variables specified in the
+        [](#opt-services.livebook.environmentFile) will supersede environment
+        variables specified in this option.
       '';
-    };
 
-    options = mkOption {
-      type = with types; attrsOf str;
-      default = { };
-      description = lib.mdDoc ''
-        Additional options to pass as command-line arguments to the server.
-      '';
       example = literalExpression ''
         {
-          cookie = "a value shared by all nodes in this cluster";
+          LIVEBOOK_PORT = 8080;
         }
       '';
     };
 
+    environmentFile = mkOption {
+      type = with types; nullOr types.path;
+      default = null;
+      description = lib.mdDoc ''
+        Additional dnvironment file as defined in {manpage}`systemd.exec(5)`.
+
+        Secrets like {env}`LIVEBOOK_PASSWORD` (which is used to specify the
+        password needed to access the livebook site) or {env}`LIVEBOOK_COOKIE`
+        (which is used to specify the
+        [cookie](https://www.erlang.org/doc/reference_manual/distributed.html#security)
+        used to connect to the running Elixir system) may be passed to the
+        service without making them readable to everyone with access to
+        systemctl by using this configuration parameter.
+
+        Note that this file needs to be available on the host on which
+        `livebook` is running.
+
+        For security purposes, this file should contain at least
+        {env}`LIVEBOOK_PASSWORD` or {env}`LIVEBOOK_TOKEN_ENABLED=false`.
+
+        See the [Livebook
+        documentation](https://hexdocs.pm/livebook/readme.html#environment-variables)
+        and the [](#opt-services.livebook.environment) configuration parameter
+        for further options.
+      '';
+      example = "/var/lib/livebook.env";
+    };
+
     extraPackages = mkOption {
       type = with types; listOf package;
       default = [ ];
@@ -81,17 +87,12 @@ in
       serviceConfig = {
         Restart = "always";
         EnvironmentFile = cfg.environmentFile;
-        ExecStart =
-          let
-            args = lib.cli.toGNUCommandLineShell { } ({
-              inherit (cfg) port;
-              ip = cfg.address;
-              name = cfg.erlang_node_name;
-              sname = cfg.erlang_node_short_name;
-            } // cfg.options);
-          in
-            "${cfg.package}/bin/livebook server ${args}";
+        ExecStart = "${cfg.package}/bin/livebook start";
+        KillMode = "mixed";
       };
+      environment = mapAttrs (name: value:
+        if isBool value then boolToString value else toString value)
+        cfg.environment;
       path = [ pkgs.bash ] ++ cfg.extraPackages;
       wantedBy = [ "default.target" ];
     };
diff --git a/nixpkgs/nixos/modules/services/editors/emacs.nix b/nixpkgs/nixos/modules/services/editors/emacs.nix
index 6f45be6640bc..ff6fd85d8a9b 100644
--- a/nixpkgs/nixos/modules/services/editors/emacs.nix
+++ b/nixpkgs/nixos/modules/services/editors/emacs.nix
@@ -15,25 +15,6 @@ let
     fi
   '';
 
-  desktopApplicationFile = pkgs.writeTextFile {
-    name = "emacsclient.desktop";
-    destination = "/share/applications/emacsclient.desktop";
-    text = ''
-      [Desktop Entry]
-      Name=Emacsclient
-      GenericName=Text Editor
-      Comment=Edit text
-      MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
-      Exec=emacseditor %F
-      Icon=emacs
-      Type=Application
-      Terminal=false
-      Categories=Development;TextEditor;
-      StartupWMClass=Emacs
-      Keywords=Text;Editor;
-    '';
-  };
-
 in
 {
 
@@ -102,7 +83,7 @@ in
       wantedBy = if cfg.startWithGraphical then [ "graphical-session.target" ] else [ "default.target" ];
     };
 
-    environment.systemPackages = [ cfg.package editorScript desktopApplicationFile ];
+    environment.systemPackages = [ cfg.package editorScript ];
 
     environment.variables.EDITOR = mkIf cfg.defaultEditor (mkOverride 900 "emacseditor");
   };
diff --git a/nixpkgs/nixos/modules/services/games/asf.nix b/nixpkgs/nixos/modules/services/games/archisteamfarm.nix
index 27d174d6726b..c00ae8116b39 100644
--- a/nixpkgs/nixos/modules/services/games/asf.nix
+++ b/nixpkgs/nixos/modules/services/games/archisteamfarm.nix
@@ -1,13 +1,11 @@
 { config, lib, pkgs, ... }:
 
-with lib;
-
 let
   cfg = config.services.archisteamfarm;
 
   format = pkgs.formats.json { };
 
-  asf-config = format.generate "ASF.json" (cfg.settings // {
+  configFile = format.generate "ASF.json" (cfg.settings // {
     # we disable it because ASF cannot update itself anyways
     # and nixos takes care of restarting the service
     # is in theory not needed as this is already the default for default builds
@@ -22,16 +20,17 @@ let
   mkBot = n: c:
     format.generate "${n}.json" (c.settings // {
       SteamLogin = if c.username == "" then n else c.username;
+      Enabled = c.enabled;
+    } // lib.optionalAttrs (c.passwordFile != null) {
       SteamPassword = c.passwordFile;
       # sets the password format to file (https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Security#file)
       PasswordFormat = 4;
-      Enabled = c.enabled;
     });
 in
 {
   options.services.archisteamfarm = {
-    enable = mkOption {
-      type = types.bool;
+    enable = lib.mkOption {
+      type = lib.types.bool;
       description = lib.mdDoc ''
         If enabled, starts the ArchisSteamFarm service.
         For configuring the SteamGuard token you will need to use the web-ui, which is enabled by default over on 127.0.0.1:1242.
@@ -40,14 +39,14 @@ in
       default = false;
     };
 
-    web-ui = mkOption {
-      type = types.submodule {
+    web-ui = lib.mkOption {
+      type = lib.types.submodule {
         options = {
-          enable = mkEnableOption "" // {
+          enable = lib.mkEnableOption "" // {
             description = lib.mdDoc "Whether to start the web-ui. This is the preferred way of configuring things such as the steam guard token.";
           };
 
-          package = mkPackageOption pkgs [ "ArchiSteamFarm" "ui" ] {
+          package = lib.mkPackageOption pkgs [ "ArchiSteamFarm" "ui" ] {
             extraDescription = ''
               ::: {.note}
               Contents must be in lib/dist
@@ -65,7 +64,7 @@ in
       description = lib.mdDoc "The Web-UI hosted on 127.0.0.1:1242.";
     };
 
-    package = mkPackageOption pkgs "ArchiSteamFarm" {
+    package = lib.mkPackageOption pkgs "ArchiSteamFarm" {
       extraDescription = ''
         ::: {.warning}
         Should always be the latest version, for security reasons,
@@ -74,15 +73,15 @@ in
       '';
     };
 
-    dataDir = mkOption {
-      type = types.path;
-      default = "/var/lib/asf";
+    dataDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/lib/archisteamfarm";
       description = lib.mdDoc ''
         The ASF home directory used to store all data.
         If left as the default value this directory will automatically be created before the ASF server starts, otherwise the sysadmin is responsible for ensuring the directory exists with appropriate ownership and permissions.'';
     };
 
-    settings = mkOption {
+    settings = lib.mkOption {
       type = format.type;
       description = lib.mdDoc ''
         The ASF.json file, all the options are documented [here](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Configuration#global-config).
@@ -96,13 +95,13 @@ in
       default = { };
     };
 
-    ipcPasswordFile = mkOption {
-      type = types.nullOr types.path;
+    ipcPasswordFile = lib.mkOption {
+      type = with lib.types; nullOr path;
       default = null;
-      description = lib.mdDoc "Path to a file containing the password. The file must be readable by the `asf` user/group.";
+      description = lib.mdDoc "Path to a file containing the password. The file must be readable by the `archisteamfarm` user/group.";
     };
 
-    ipcSettings = mkOption {
+    ipcSettings = lib.mkOption {
       type = format.type;
       description = lib.mdDoc ''
         Settings to write to IPC.config.
@@ -120,25 +119,29 @@ in
       default = { };
     };
 
-    bots = mkOption {
-      type = types.attrsOf (types.submodule {
+    bots = lib.mkOption {
+      type = lib.types.attrsOf (lib.types.submodule {
         options = {
-          username = mkOption {
-            type = types.str;
+          username = lib.mkOption {
+            type = lib.types.str;
             description = lib.mdDoc "Name of the user to log in. Default is attribute name.";
             default = "";
           };
-          passwordFile = mkOption {
-            type = types.path;
-            description = lib.mdDoc "Path to a file containing the password. The file must be readable by the `asf` user/group.";
+          passwordFile = lib.mkOption {
+            type = with lib.types; nullOr path;
+            default = null;
+            description = lib.mdDoc ''
+              Path to a file containing the password. The file must be readable by the `archisteamfarm` user/group.
+              Omit or set to null to provide the password a different way, such as through the web-ui.
+            '';
           };
-          enabled = mkOption {
-            type = types.bool;
+          enabled = lib.mkOption {
+            type = lib.types.bool;
             default = true;
             description = lib.mdDoc "Whether to enable the bot on startup.";
           };
-          settings = mkOption {
-            type = types.attrs;
+          settings = lib.mkOption {
+            type = lib.types.attrs;
             description = lib.mdDoc ''
               Additional settings that are documented [here](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Configuration#bot-config).
             '';
@@ -152,7 +155,7 @@ in
       example = {
         exampleBot = {
           username = "alice";
-          passwordFile = "/var/lib/asf/secrets/password";
+          passwordFile = "/var/lib/archisteamfarm/secrets/password";
           settings = { SteamParentalCode = "1234"; };
         };
       };
@@ -160,32 +163,34 @@ in
     };
   };
 
-  config = mkIf cfg.enable {
+  config = lib.mkIf cfg.enable {
+    # TODO: drop with 24.11
+    services.archisteamfarm.dataDir = lib.mkIf (lib.versionAtLeast config.system.stateVersion "24.05") (lib.mkDefault "/var/lib/asf");
 
     users = {
-      users.asf = {
+      users.archisteamfarm = {
         home = cfg.dataDir;
         isSystemUser = true;
-        group = "asf";
+        group = "archisteamfarm";
         description = "Archis-Steam-Farm service user";
       };
-      groups.asf = { };
+      groups.archisteamfarm = { };
     };
 
     systemd.services = {
-      asf = {
+      archisteamfarm = {
         description = "Archis-Steam-Farm Service";
         after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
 
-        serviceConfig = mkMerge [
-          (mkIf (cfg.dataDir == "/var/lib/asf") {
-            StateDirectory = "asf";
+        serviceConfig = lib.mkMerge [
+          (lib.mkIf (lib.hasPrefix "/var/lib/" cfg.dataDir) {
+            StateDirectory = lib.last (lib.splitString "/" cfg.dataDir);
             StateDirectoryMode = "700";
           })
           {
-            User = "asf";
-            Group = "asf";
+            User = "archisteamfarm";
+            Group = "archisteamfarm";
             WorkingDirectory = cfg.dataDir;
             Type = "simple";
             ExecStart = "${lib.getExe cfg.package} --no-restart --process-required --service --system-required --path ${cfg.dataDir}";
@@ -217,12 +222,10 @@ in
             RestrictNamespaces = true;
             RestrictRealtime = true;
             RestrictSUIDSGID = true;
-            SystemCallArchitectures = "native";
-            UMask = "0077";
-
-            # we luckily already have systemd v247+
             SecureBits = "noroot-locked";
+            SystemCallArchitectures = "native";
             SystemCallFilter = [ "@system-service" "~@privileged" ];
+            UMask = "0077";
           }
         ];
 
@@ -232,7 +235,7 @@ in
               mkdir -p $out
               # clean potential removed bots
               rm -rf $out/*.json
-              for i in ${strings.concatStringsSep " " (lists.map (x: "${getName x},${x}") (attrsets.mapAttrsToList mkBot cfg.bots))}; do IFS=",";
+              for i in ${lib.concatStringsSep " " (map (x: "${lib.getName x},${x}") (lib.mapAttrsToList mkBot cfg.bots))}; do IFS=",";
                 set -- $i
                 ln -fs $2 $out/$1
               done
@@ -242,22 +245,22 @@ in
           ''
             mkdir -p config
 
-            cp --no-preserve=mode ${asf-config} config/ASF.json
+            cp --no-preserve=mode ${configFile} config/ASF.json
 
-            ${optionalString (cfg.ipcPasswordFile != null) ''
+            ${lib.optionalString (cfg.ipcPasswordFile != null) ''
               ${replaceSecretBin} '#ipcPassword#' '${cfg.ipcPasswordFile}' config/ASF.json
             ''}
 
-            ${optionalString (cfg.ipcSettings != {}) ''
+            ${lib.optionalString (cfg.ipcSettings != {}) ''
               ln -fs ${ipc-config} config/IPC.config
             ''}
 
-            ${optionalString (cfg.ipcSettings != {}) ''
+            ${lib.optionalString (cfg.ipcSettings != {}) ''
               ln -fs ${createBotsScript}/* config/
             ''}
 
             rm -f www
-            ${optionalString cfg.web-ui.enable ''
+            ${lib.optionalString cfg.web-ui.enable ''
               ln -s ${cfg.web-ui.package}/ www
             ''}
           '';
@@ -267,6 +270,6 @@ in
 
   meta = {
     buildDocsInSandbox = false;
-    maintainers = with maintainers; [ lom SuperSandro2000 ];
+    maintainers = with lib.maintainers; [ lom SuperSandro2000 ];
   };
 }
diff --git a/nixpkgs/nixos/modules/services/hardware/acpid.nix b/nixpkgs/nixos/modules/services/hardware/acpid.nix
index 6021aad09f45..821f4ef205fc 100644
--- a/nixpkgs/nixos/modules/services/hardware/acpid.nix
+++ b/nixpkgs/nixos/modules/services/hardware/acpid.nix
@@ -135,7 +135,6 @@ in
       wantedBy = [ "multi-user.target" ];
 
       serviceConfig = {
-        PrivateNetwork = true;
         ExecStart = escapeShellArgs
           ([ "${pkgs.acpid}/bin/acpid"
              "--foreground"
diff --git a/nixpkgs/nixos/modules/services/hardware/fwupd.nix b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
index 6b3a109ed6f7..8a9e38d0547b 100644
--- a/nixpkgs/nixos/modules/services/hardware/fwupd.nix
+++ b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
@@ -16,6 +16,7 @@ let
     "fwupd/fwupd.conf" = {
       source = format.generate "fwupd.conf" {
         fwupd = cfg.daemonSettings;
+      } // lib.optionalAttrs (lib.length (lib.attrNames cfg.uefiCapsuleSettings) != 0) {
         uefi_capsule = cfg.uefiCapsuleSettings;
       };
       # fwupd tries to chmod the file if it doesn't have the right permissions
@@ -50,7 +51,9 @@ let
     # to install it because it would create a cyclic dependency between
     # the outputs. We also need to enable the remote,
     # which should not be done by default.
-    lib.optionalAttrs cfg.enableTestRemote (enableRemote cfg.package.installedTests "fwupd-tests")
+    lib.optionalAttrs
+      (cfg.daemonSettings.TestDevices or false)
+      (enableRemote cfg.package.installedTests "fwupd-tests")
   );
 
 in {
@@ -85,15 +88,6 @@ in {
         '';
       };
 
-      enableTestRemote = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Whether to enable test remote. This is used by
-          [installed tests](https://github.com/fwupd/fwupd/blob/master/data/installed-tests/README.md).
-        '';
-      };
-
       package = mkPackageOption pkgs "fwupd" { };
 
       daemonSettings = mkOption {
@@ -127,6 +121,16 @@ in {
                 or if this partition is not mounted at /boot/efi, /boot, or /efi
               '';
             };
+
+            TestDevices = mkOption {
+              internal = true;
+              type = types.bool;
+              default = false;
+              description = lib.mdDoc ''
+                Create virtual test devices and remote for validating daemon flows.
+                This is only intended for CI testing and development purposes.
+              '';
+            };
           };
         };
         default = {};
@@ -152,13 +156,13 @@ in {
     (mkRenamedOptionModule [ "services" "fwupd" "blacklistPlugins"] [ "services" "fwupd" "daemonSettings" "DisabledPlugins" ])
     (mkRenamedOptionModule [ "services" "fwupd" "disabledDevices" ] [ "services" "fwupd" "daemonSettings" "DisabledDevices" ])
     (mkRenamedOptionModule [ "services" "fwupd" "disabledPlugins" ] [ "services" "fwupd" "daemonSettings" "DisabledPlugins" ])
+    (mkRemovedOptionModule [ "services" "fwupd" "enableTestRemote" ] "This option was removed after being removed upstream. It only provided a method for testing fwupd functionality, and should not have been exposed for use outside of nix tests.")
   ];
 
   ###### implementation
   config = mkIf cfg.enable {
     # Disable test related plug-ins implicitly so that users do not have to care about them.
     services.fwupd.daemonSettings = {
-      DisabledPlugins = cfg.package.defaultDisabledPlugins;
       EspLocation = config.boot.loader.efi.efiSysMountPoint;
     };
 
diff --git a/nixpkgs/nixos/modules/services/hardware/handheld-daemon.nix b/nixpkgs/nixos/modules/services/hardware/handheld-daemon.nix
new file mode 100644
index 000000000000..e8a7a39f441d
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/handheld-daemon.nix
@@ -0,0 +1,44 @@
+{ config
+, lib
+, pkgs
+, ...
+}:
+with lib; let
+  cfg = config.services.handheld-daemon;
+in
+{
+  options.services.handheld-daemon = {
+    enable = mkEnableOption "Enable Handheld Daemon";
+    package = mkPackageOption pkgs "handheld-daemon" { };
+
+    user = mkOption {
+      type = types.str;
+      description = lib.mdDoc ''
+        The user to run Handheld Daemon with.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ cfg.package ];
+    services.udev.packages = [ cfg.package ];
+    systemd.packages = [ cfg.package ];
+
+    systemd.services.handheld-daemon = {
+      description = "Handheld Daemon";
+
+      wantedBy = [ "multi-user.target" ];
+
+      restartIfChanged = true;
+
+      serviceConfig = {
+        ExecStart = "${ lib.getExe cfg.package } --user ${ cfg.user }";
+        Nice = "-12";
+        Restart = "on-failure";
+        RestartSec = "10";
+      };
+    };
+  };
+
+  meta.maintainers = [ maintainers.appsforartists ];
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/pcscd.nix b/nixpkgs/nixos/modules/services/hardware/pcscd.nix
index 85accd8335f7..b5963e1d29a3 100644
--- a/nixpkgs/nixos/modules/services/hardware/pcscd.nix
+++ b/nixpkgs/nixos/modules/services/hardware/pcscd.nix
@@ -46,8 +46,8 @@ in
   config = mkIf config.services.pcscd.enable {
     environment.etc."reader.conf".source = cfgFile;
 
-    environment.systemPackages = [ package.out ];
-    systemd.packages = [ (getBin package) ];
+    environment.systemPackages = [ package ];
+    systemd.packages = [ package ];
 
     services.pcscd.plugins = [ pkgs.ccid ];
 
@@ -64,7 +64,7 @@ in
       # around it, we force the path to the cfgFile.
       #
       # https://github.com/NixOS/nixpkgs/issues/121088
-      serviceConfig.ExecStart = [ "" "${getBin package}/bin/pcscd -f -x -c ${cfgFile}" ];
+      serviceConfig.ExecStart = [ "" "${package}/bin/pcscd -f -x -c ${cfgFile}" ];
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/hardware/ratbagd.nix b/nixpkgs/nixos/modules/services/hardware/ratbagd.nix
index c939d5e40a24..5567bcbafd16 100644
--- a/nixpkgs/nixos/modules/services/hardware/ratbagd.nix
+++ b/nixpkgs/nixos/modules/services/hardware/ratbagd.nix
@@ -11,6 +11,8 @@ in
   options = {
     services.ratbagd = {
       enable = mkEnableOption (lib.mdDoc "ratbagd for configuring gaming mice");
+
+      package = mkPackageOption pkgs "libratbag" { };
     };
   };
 
@@ -18,10 +20,10 @@ in
 
   config = mkIf cfg.enable {
     # Give users access to the "ratbagctl" tool
-    environment.systemPackages = [ pkgs.libratbag ];
+    environment.systemPackages = [ cfg.package ];
 
-    services.dbus.packages = [ pkgs.libratbag ];
+    services.dbus.packages = [ cfg.package ];
 
-    systemd.packages = [ pkgs.libratbag ];
+    systemd.packages = [ cfg.package ];
   };
 }
diff --git a/nixpkgs/nixos/modules/services/home-automation/esphome.nix b/nixpkgs/nixos/modules/services/home-automation/esphome.nix
index 4fc007a97683..3c0fd8aed08a 100644
--- a/nixpkgs/nixos/modules/services/home-automation/esphome.nix
+++ b/nixpkgs/nixos/modules/services/home-automation/esphome.nix
@@ -63,6 +63,12 @@ in
       '';
       type = types.listOf types.str;
     };
+
+    usePing = mkOption {
+      default = false;
+      type = types.bool;
+      description = lib.mdDoc "Use ping to check online status of devices instead of mDNS";
+    };
   };
 
   config = mkIf cfg.enable {
@@ -74,8 +80,10 @@ in
       wantedBy = ["multi-user.target"];
       path = [cfg.package];
 
-      # platformio fails to determine the home directory when using DynamicUser
-      environment.PLATFORMIO_CORE_DIR = "${stateDir}/.platformio";
+      environment = {
+        # platformio fails to determine the home directory when using DynamicUser
+        PLATFORMIO_CORE_DIR = "${stateDir}/.platformio";
+      } // lib.optionalAttrs cfg.usePing { ESPHOME_DASHBOARD_USE_PING = "true"; };
 
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/esphome dashboard ${esphomeParams} ${stateDir}";
diff --git a/nixpkgs/nixos/modules/services/home-automation/evcc.nix b/nixpkgs/nixos/modules/services/home-automation/evcc.nix
index d0ce3fb4a1ce..f360f525b04b 100644
--- a/nixpkgs/nixos/modules/services/home-automation/evcc.nix
+++ b/nixpkgs/nixos/modules/services/home-automation/evcc.nix
@@ -41,6 +41,7 @@ in
 
   config = mkIf cfg.enable {
     systemd.services.evcc = {
+      wants = [ "network-online.target" ];
       after = [
         "network-online.target"
         "mosquitto.target"
diff --git a/nixpkgs/nixos/modules/services/home-automation/govee2mqtt.nix b/nixpkgs/nixos/modules/services/home-automation/govee2mqtt.nix
new file mode 100644
index 000000000000..1dee5999fa3b
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/home-automation/govee2mqtt.nix
@@ -0,0 +1,90 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.govee2mqtt;
+in {
+  meta.maintainers = with lib.maintainers; [ SuperSandro2000 ];
+
+  options.services.govee2mqtt = {
+    enable = lib.mkEnableOption "Govee2MQTT";
+
+    package = lib.mkPackageOption pkgs "govee2mqtt" { };
+
+    user = lib.mkOption {
+      type = lib.types.str;
+      default = "govee2mqtt";
+      description = "User under which Govee2MQTT should run.";
+    };
+
+    group = lib.mkOption {
+      type = lib.types.str;
+      default = "govee2mqtt";
+      description = "Group under which Govee2MQTT should run.";
+    };
+
+    environmentFile = lib.mkOption {
+      type = lib.types.path;
+      example = "/var/lib/govee2mqtt/govee2mqtt.env";
+      description = ''
+        Environment file as defined in {manpage}`systemd.exec(5)`.
+
+        See upstream documentation <https://github.com/wez/govee2mqtt/blob/main/docs/CONFIG.md>.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    users = {
+      groups.${cfg.group} = { };
+      users.${cfg.user} = {
+        description = "Govee2MQTT service user";
+        inherit (cfg) group;
+        isSystemUser = true;
+      };
+    };
+
+    systemd.services.govee2mqtt = {
+      description = "Govee2MQTT Service";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "networking.target" ];
+      serviceConfig = {
+        CacheDirectory = "govee2mqtt";
+        Environment = [
+          "GOVEE_CACHE_DIR=/var/cache/govee2mqtt"
+        ];
+        EnvironmentFile = cfg.environmentFile;
+        ExecStart = "${lib.getExe cfg.package} serve --govee-iot-key=/var/lib/govee2mqtt/iot.key --govee-iot-cert=/var/lib/govee2mqtt/iot.cert"
+          + " --amazon-root-ca=${pkgs.cacert.unbundled}/etc/ssl/certs/Amazon_Root_CA_1:66c9fcf99bf8c0a39e2f0788a43e696365bca.crt";
+        Group = cfg.group;
+        Restart = "on-failure";
+        StateDirectory = "govee2mqtt";
+        User = cfg.user;
+
+        # Hardening
+        AmbientCapabilities = "";
+        CapabilityBoundingSet = "";
+        LockPersonality = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateMounts = true;
+        PrivateTmp = true;
+        PrivateUsers = true;
+        ProcSubset = "pid";
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        ProtectSystem = "strict";
+        RemoveIPC = true;
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix b/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix
index bc470576b759..3423eebe9ed6 100644
--- a/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix
+++ b/nixpkgs/nixos/modules/services/home-automation/home-assistant.nix
@@ -52,7 +52,7 @@ let
     hasAttrByPath (splitString "." component) cfg.config
     || useComponentPlatform component
     || useExplicitComponent component
-    || builtins.elem component cfg.extraComponents;
+    || builtins.elem component (cfg.extraComponents ++ cfg.defaultIntegrations);
 
   # Final list of components passed into the package to include required dependencies
   extraComponents = filter useComponent availableComponents;
@@ -103,6 +103,45 @@ in {
       description = lib.mdDoc "The config directory, where your {file}`configuration.yaml` is located.";
     };
 
+    defaultIntegrations = mkOption {
+      type = types.listOf (types.enum availableComponents);
+      # https://github.com/home-assistant/core/blob/dev/homeassistant/bootstrap.py#L109
+      default = [
+        "application_credentials"
+        "frontend"
+        "hardware"
+        "logger"
+        "network"
+        "system_health"
+
+        # key features
+        "automation"
+        "person"
+        "scene"
+        "script"
+        "tag"
+        "zone"
+
+        # built-in helpers
+        "counter"
+        "input_boolean"
+        "input_button"
+        "input_datetime"
+        "input_number"
+        "input_select"
+        "input_text"
+        "schedule"
+        "timer"
+
+        # non-supervisor
+        "backup"
+      ];
+      readOnly = true;
+      description = ''
+        List of integrations set are always set up, unless in recovery mode.
+      '';
+    };
+
     extraComponents = mkOption {
       type = types.listOf (types.enum availableComponents);
       default = [
@@ -435,6 +474,7 @@ in {
 
     systemd.services.home-assistant = {
       description = "Home Assistant";
+      wants = [ "network-online.target" ];
       after = [
         "network-online.target"
 
@@ -532,6 +572,7 @@ in {
           "inkbird"
           "improv_ble"
           "keymitt_ble"
+          "leaone-ble"
           "led_ble"
           "medcom_ble"
           "melnor"
diff --git a/nixpkgs/nixos/modules/services/logging/journaldriver.nix b/nixpkgs/nixos/modules/services/logging/journaldriver.nix
index 59eedff90d60..4d21464018aa 100644
--- a/nixpkgs/nixos/modules/services/logging/journaldriver.nix
+++ b/nixpkgs/nixos/modules/services/logging/journaldriver.nix
@@ -84,6 +84,7 @@ in {
     systemd.services.journaldriver = {
       description = "Stackdriver Logging journal forwarder";
       script      = "${pkgs.journaldriver}/bin/journaldriver";
+      wants       = [ "network-online.target" ];
       after       = [ "network-online.target" ];
       wantedBy    = [ "multi-user.target" ];
 
diff --git a/nixpkgs/nixos/modules/services/mail/dovecot.nix b/nixpkgs/nixos/modules/services/mail/dovecot.nix
index 25c7017a1d25..71baa2bb1852 100644
--- a/nixpkgs/nixos/modules/services/mail/dovecot.nix
+++ b/nixpkgs/nixos/modules/services/mail/dovecot.nix
@@ -1,10 +1,12 @@
-{ options, config, lib, pkgs, ... }:
+{ config, lib, pkgs, ... }:
 
 let
-  inherit (lib) any attrValues concatMapStringsSep concatStrings
-    concatStringsSep flatten imap1 isList literalExpression mapAttrsToList
+  inherit (lib) attrValues concatMapStringsSep concatStrings
+    concatStringsSep flatten imap1 literalExpression mapAttrsToList
     mkEnableOption mkIf mkOption mkRemovedOptionModule optional optionalAttrs
-    optionalString singleton types;
+    optionalString singleton types mkRenamedOptionModule nameValuePair
+    mapAttrs' listToAttrs filter;
+  inherit (lib.strings) match;
 
   cfg = config.services.dovecot2;
   dovecotPkg = pkgs.dovecot;
@@ -12,6 +14,58 @@ let
   baseDir = "/run/dovecot2";
   stateDir = "/var/lib/dovecot";
 
+  sieveScriptSettings = mapAttrs' (to: _: nameValuePair "sieve_${to}" "${stateDir}/sieve/${to}") cfg.sieve.scripts;
+  imapSieveMailboxSettings = listToAttrs (flatten (imap1 (idx: el:
+    singleton {
+      name = "imapsieve_mailbox${toString idx}_name";
+      value = el.name;
+    } ++ optional (el.from != null) {
+      name = "imapsieve_mailbox${toString idx}_from";
+      value = el.from;
+    } ++ optional (el.causes != []) {
+      name = "imapsieve_mailbox${toString idx}_causes";
+      value = concatStringsSep "," el.causes;
+    } ++ optional (el.before != null) {
+      name = "imapsieve_mailbox${toString idx}_before";
+      value = "file:${stateDir}/imapsieve/before/${baseNameOf el.before}";
+    } ++ optional (el.after != null) {
+      name = "imapsieve_mailbox${toString idx}_after";
+      value = "file:${stateDir}/imapsieve/after/${baseNameOf el.after}";
+    }
+  ) cfg.imapsieve.mailbox));
+
+  mkExtraConfigCollisionWarning = term: ''
+    You referred to ${term} in `services.dovecot2.extraConfig`.
+
+    Due to gradual transition to structured configuration for plugin configuration, it is possible
+    this will cause your plugin configuration to be ignored.
+
+    Consider setting `services.dovecot2.pluginSettings.${term}` instead.
+  '';
+
+  # Those settings are automatically set based on other parts
+  # of this module.
+  automaticallySetPluginSettings = [
+    "sieve_plugins"
+    "sieve_extensions"
+    "sieve_global_extensions"
+    "sieve_pipe_bin_dir"
+  ]
+  ++ (builtins.attrNames sieveScriptSettings)
+  ++ (builtins.attrNames imapSieveMailboxSettings);
+
+  # The idea is to match everything that looks like `$term =`
+  # but not `# $term something something`
+  # or `# $term = some value` because those are comments.
+  configContainsSetting = lines: term: (match "^[^#]*\b${term}\b.*=" lines) != null;
+
+  warnAboutExtraConfigCollisions = map mkExtraConfigCollisionWarning (filter (configContainsSetting cfg.extraConfig) automaticallySetPluginSettings);
+
+  sievePipeBinScriptDirectory = pkgs.linkFarm "sieve-pipe-bins" (map (el: {
+      name = builtins.unsafeDiscardStringContext (baseNameOf el);
+      path = el;
+  }) cfg.sieve.pipeBins);
+
   dovecotConf = concatStrings [
     ''
       base_dir = ${baseDir}
@@ -78,14 +132,6 @@ let
     )
 
     (
-      optionalString (cfg.sieveScripts != {}) ''
-        plugin {
-          ${concatStringsSep "\n" (mapAttrsToList (to: from: "sieve_${to} = ${stateDir}/sieve/${to}") cfg.sieveScripts)}
-        }
-      ''
-    )
-
-    (
       optionalString (cfg.mailboxes != {}) ''
         namespace inbox {
           inbox=yes
@@ -116,33 +162,12 @@ let
       ''
     )
 
+    # General plugin settings:
+    # - sieve is mostly generated here, refer to `pluginSettings` to follow
+    # the control flow.
     ''
       plugin {
-        sieve_plugins = ${concatStringsSep " " cfg.sieve.plugins}
-        sieve_extensions = ${concatStringsSep " " (map (el: "+${el}") cfg.sieve.extensions)}
-        sieve_global_extensions = ${concatStringsSep " " (map (el: "+${el}") cfg.sieve.globalExtensions)}
-    ''
-    (optionalString (cfg.imapsieve.mailbox != []) ''
-      ${
-        concatStringsSep "\n" (flatten (imap1 (
-            idx: el:
-              singleton "imapsieve_mailbox${toString idx}_name = ${el.name}"
-              ++ optional (el.from != null) "imapsieve_mailbox${toString idx}_from = ${el.from}"
-              ++ optional (el.causes != null) "imapsieve_mailbox${toString idx}_causes = ${el.causes}"
-              ++ optional (el.before != null) "imapsieve_mailbox${toString idx}_before = file:${stateDir}/imapsieve/before/${baseNameOf el.before}"
-              ++ optional (el.after != null) "imapsieve_mailbox${toString idx}_after = file:${stateDir}/imapsieve/after/${baseNameOf el.after}"
-          )
-          cfg.imapsieve.mailbox))
-      }
-    '')
-    (optionalString (cfg.sieve.pipeBins != []) ''
-        sieve_pipe_bin_dir = ${pkgs.linkFarm "sieve-pipe-bins" (map (el: {
-          name = builtins.unsafeDiscardStringContext (baseNameOf el);
-          path = el;
-        })
-        cfg.sieve.pipeBins)}
-    '')
-    ''
+        ${concatStringsSep "\n" (mapAttrsToList (key: value: "  ${key} = ${value}") cfg.pluginSettings)}
       }
     ''
 
@@ -199,6 +224,7 @@ in
 {
   imports = [
     (mkRemovedOptionModule [ "services" "dovecot2" "package" ] "")
+    (mkRenamedOptionModule [ "services" "dovecot2" "sieveScripts" ] [ "services" "dovecot2" "sieve" "scripts" ])
   ];
 
   options.services.dovecot2 = {
@@ -337,12 +363,6 @@ in
 
     enableDHE = mkEnableOption (lib.mdDoc "ssl_dh and generation of primes for the key exchange") // { default = true; };
 
-    sieveScripts = mkOption {
-      type = types.attrsOf types.path;
-      default = {};
-      description = lib.mdDoc "Sieve scripts to be executed. Key is a sequence, e.g. 'before2', 'after' etc.";
-    };
-
     showPAMFailure = mkEnableOption (lib.mdDoc "showing the PAM failure message on authentication error (useful for OTPW)");
 
     mailboxes = mkOption {
@@ -376,6 +396,26 @@ in
       description = lib.mdDoc "Quota limit for the user in bytes. Supports suffixes b, k, M, G, T and %.";
     };
 
+
+    pluginSettings = mkOption {
+      # types.str does not coerce from packages, like `sievePipeBinScriptDirectory`.
+      type = types.attrsOf (types.oneOf [ types.str types.package ]);
+      default = {};
+      example = literalExpression ''
+        {
+          sieve = "file:~/sieve;active=~/.dovecot.sieve";
+        }
+      '';
+      description = ''
+        Plugin settings for dovecot in general, e.g. `sieve`, `sieve_default`, etc.
+
+        Some of the other knobs of this module will influence by default the plugin settings, but you
+        can still override any plugin settings.
+
+        If you override a plugin setting, its value is cleared and you have to copy over the defaults.
+      '';
+    };
+
     imapsieve.mailbox = mkOption {
       default = [];
       description = "Configure Sieve filtering rules on IMAP actions";
@@ -405,14 +445,14 @@ in
           };
 
           causes = mkOption {
-            default = null;
+            default = [ ];
             description = ''
               Only execute the administrator Sieve scripts for the mailbox configured with services.dovecot2.imapsieve.mailbox.<name>.name when one of the listed IMAPSIEVE causes apply.
 
               This has no effect on the user script, which is always executed no matter the cause.
             '';
-            example = "COPY";
-            type = types.nullOr (types.enum [ "APPEND" "COPY" "FLAG" ]);
+            example = [ "COPY" "APPEND" ];
+            type = types.listOf (types.enum [ "APPEND" "COPY" "FLAG" ]);
           };
 
           before = mkOption {
@@ -462,6 +502,12 @@ in
         type = types.listOf types.str;
       };
 
+      scripts = mkOption {
+        type = types.attrsOf types.path;
+        default = {};
+        description = lib.mdDoc "Sieve scripts to be executed. Key is a sequence, e.g. 'before2', 'after' etc.";
+      };
+
       pipeBins = mkOption {
         default = [];
         example = literalExpression ''
@@ -476,7 +522,6 @@ in
     };
   };
 
-
   config = mkIf cfg.enable {
     security.pam.services.dovecot2 = mkIf cfg.enablePAM {};
 
@@ -501,6 +546,13 @@ in
         ++ optional (cfg.sieve.pipeBins != []) "sieve_extprograms";
 
       sieve.globalExtensions = optional (cfg.sieve.pipeBins != []) "vnd.dovecot.pipe";
+
+      pluginSettings = lib.mapAttrs (n: lib.mkDefault) ({
+        sieve_plugins = concatStringsSep " " cfg.sieve.plugins;
+        sieve_extensions = concatStringsSep " " (map (el: "+${el}") cfg.sieve.extensions);
+        sieve_global_extensions = concatStringsSep " " (map (el: "+${el}") cfg.sieve.globalExtensions);
+        sieve_pipe_bin_dir = sievePipeBinScriptDirectory;
+      } // sieveScriptSettings // imapSieveMailboxSettings);
     };
 
     users.users = {
@@ -556,7 +608,7 @@ in
       # the source file and Dovecot won't try to compile it.
       preStart = ''
         rm -rf ${stateDir}/sieve ${stateDir}/imapsieve
-      '' + optionalString (cfg.sieveScripts != {}) ''
+      '' + optionalString (cfg.sieve.scripts != {}) ''
         mkdir -p ${stateDir}/sieve
         ${concatStringsSep "\n" (
         mapAttrsToList (
@@ -569,7 +621,7 @@ in
             fi
             ${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/sieve/${to}'
           ''
-        ) cfg.sieveScripts
+        ) cfg.sieve.scripts
       )}
         chown -R '${cfg.mailUser}:${cfg.mailGroup}' '${stateDir}/sieve'
       ''
@@ -600,9 +652,7 @@ in
 
     environment.systemPackages = [ dovecotPkg ];
 
-    warnings = mkIf (any isList options.services.dovecot2.mailboxes.definitions) [
-      "Declaring `services.dovecot2.mailboxes' as a list is deprecated and will break eval in 21.05! See the release notes for more info for migration."
-    ];
+    warnings = warnAboutExtraConfigCollisions;
 
     assertions = [
       {
@@ -615,8 +665,8 @@ in
         message = "dovecot is configured with showPAMFailure while enablePAM is disabled";
       }
       {
-        assertion = cfg.sieveScripts != {} -> (cfg.mailUser != null && cfg.mailGroup != null);
-        message = "dovecot requires mailUser and mailGroup to be set when sieveScripts is set";
+        assertion = cfg.sieve.scripts != {} -> (cfg.mailUser != null && cfg.mailGroup != null);
+        message = "dovecot requires mailUser and mailGroup to be set when `sieve.scripts` is set";
       }
     ];
 
diff --git a/nixpkgs/nixos/modules/services/mail/mlmmj.nix b/nixpkgs/nixos/modules/services/mail/mlmmj.nix
index 3f07fabcf177..66106a14499b 100644
--- a/nixpkgs/nixos/modules/services/mail/mlmmj.nix
+++ b/nixpkgs/nixos/modules/services/mail/mlmmj.nix
@@ -143,11 +143,13 @@ in
 
     environment.systemPackages = [ pkgs.mlmmj ];
 
-    systemd.tmpfiles.rules = [
-      ''d "${stateDir}" -''
-      ''d "${spoolDir}/${cfg.listDomain}" -''
-      ''Z "${spoolDir}" - "${cfg.user}" "${cfg.group}" -''
-    ];
+    systemd.tmpfiles.settings."10-mlmmj" = {
+      ${stateDir}.d = { };
+      "${spoolDir}/${cfg.listDomain}".d = { };
+      ${spoolDir}.Z = {
+        inherit (cfg) user group;
+      };
+    };
 
     systemd.services.mlmmj-maintd = {
       description = "mlmmj maintenance daemon";
diff --git a/nixpkgs/nixos/modules/services/mail/postfixadmin.nix b/nixpkgs/nixos/modules/services/mail/postfixadmin.nix
index b86428770cb2..e7ebb6fbd648 100644
--- a/nixpkgs/nixos/modules/services/mail/postfixadmin.nix
+++ b/nixpkgs/nixos/modules/services/mail/postfixadmin.nix
@@ -99,7 +99,11 @@ in
       ${cfg.extraConfig}
     '';
 
-    systemd.tmpfiles.rules = [ "d /var/cache/postfixadmin/templates_c 700 ${user} ${user}" ];
+    systemd.tmpfiles.settings."10-postfixadmin"."/var/cache/postfixadmin/templates_c".d = {
+      inherit user;
+      group = user;
+      mode = "700";
+    };
 
     services.nginx = {
       enable = true;
diff --git a/nixpkgs/nixos/modules/services/mail/roundcube.nix b/nixpkgs/nixos/modules/services/mail/roundcube.nix
index c883c143e523..3f1a695ab91a 100644
--- a/nixpkgs/nixos/modules/services/mail/roundcube.nix
+++ b/nixpkgs/nixos/modules/services/mail/roundcube.nix
@@ -250,6 +250,7 @@ in
         path = [ config.services.postgresql.package ];
       })
       {
+        wants = [ "network-online.target" ];
         after = [ "network-online.target" ];
         wantedBy = [ "multi-user.target" ];
         script = let
diff --git a/nixpkgs/nixos/modules/services/mail/sympa.nix b/nixpkgs/nixos/modules/services/mail/sympa.nix
index 04ae46f66eea..13fc8656a2b5 100644
--- a/nixpkgs/nixos/modules/services/mail/sympa.nix
+++ b/nixpkgs/nixos/modules/services/mail/sympa.nix
@@ -435,7 +435,7 @@ in
 
       wantedBy = [ "multi-user.target" ];
       after = [ "network-online.target" ];
-      wants = sympaSubServices;
+      wants = sympaSubServices ++ [ "network-online.target" ];
       before = sympaSubServices;
       serviceConfig = sympaServiceConfig "sympa_msg";
 
diff --git a/nixpkgs/nixos/modules/services/mail/zeyple.nix b/nixpkgs/nixos/modules/services/mail/zeyple.nix
index e7f9ddd92dc2..9d4bc7f712d6 100644
--- a/nixpkgs/nixos/modules/services/mail/zeyple.nix
+++ b/nixpkgs/nixos/modules/services/mail/zeyple.nix
@@ -93,7 +93,11 @@ in {
 
     environment.etc."zeyple.conf".source = ini.generate "zeyple.conf" cfg.settings;
 
-    systemd.tmpfiles.rules = [ "f '${cfg.settings.zeyple.log_file}' 0600 ${cfg.user} ${cfg.group} - -" ];
+    systemd.tmpfiles.settings."10-zeyple".${cfg.settings.zeyple.log_file}.f = {
+      inherit (cfg) user group;
+      mode = "0600";
+    };
+
     services.logrotate = mkIf cfg.rotateLogs {
       enable = true;
       settings.zeyple = {
diff --git a/nixpkgs/nixos/modules/services/matrix/hebbot.nix b/nixpkgs/nixos/modules/services/matrix/hebbot.nix
new file mode 100644
index 000000000000..ebf175464ddd
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/matrix/hebbot.nix
@@ -0,0 +1,78 @@
+{ lib
+, config
+, pkgs
+, ...
+}:
+
+let
+  inherit (lib) mkEnableOption mkOption mkIf types;
+  format = pkgs.formats.toml { };
+  cfg = config.services.hebbot;
+  settingsFile = format.generate "config.toml" cfg.settings;
+  mkTemplateOption = templateName: mkOption {
+    type = types.path;
+    description = lib.mdDoc ''
+      A path to the Markdown file for the ${templateName}.
+    '';
+  };
+in
+  {
+    meta.maintainers = [ lib.maintainers.raitobezarius ];
+    options.services.hebbot = {
+      enable = mkEnableOption "hebbot";
+      botPasswordFile = mkOption {
+        type = types.path;
+        description = lib.mdDoc ''
+          A path to the password file for your bot.
+
+          Consider using a path that does not end up in your Nix store
+          as it would be world readable.
+        '';
+      };
+      templates = {
+        project = mkTemplateOption "project template";
+        report = mkTemplateOption "report template";
+        section = mkTemplateOption "section template";
+      };
+      settings = mkOption {
+        type = format.type;
+        default = { };
+        description = lib.mdDoc ''
+          Configuration for Hebbot, see, for examples:
+
+          - <https://github.com/matrix-org/twim-config/blob/master/config.toml>
+          - <https://gitlab.gnome.org/Teams/Websites/thisweek.gnome.org/-/blob/main/hebbot/config.toml>
+        '';
+      };
+    };
+
+    config = mkIf cfg.enable {
+      systemd.services.hebbot = {
+        description = "hebbot - a TWIM-style Matrix bot written in Rust";
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+
+        preStart = ''
+          ln -sf ${cfg.templates.project} ./project_template.md
+          ln -sf ${cfg.templates.report} ./report_template.md
+          ln -sf ${cfg.templates.section} ./section_template.md
+          ln -sf ${settingsFile} ./config.toml
+        '';
+
+        script = ''
+          export BOT_PASSWORD="$(cat $CREDENTIALS_DIRECTORY/bot-password-file)"
+          ${lib.getExe pkgs.hebbot}
+        '';
+
+        serviceConfig = {
+          DynamicUser = true;
+          Restart = "on-failure";
+          LoadCredential = "bot-password-file:${cfg.botPasswordFile}";
+          RestartSec = "10s";
+          StateDirectory = "hebbot";
+          WorkingDirectory = "hebbot";
+      };
+    };
+  };
+}
+
diff --git a/nixpkgs/nixos/modules/services/matrix/synapse.md b/nixpkgs/nixos/modules/services/matrix/synapse.md
index f270be8c8d78..9c9c025fc5f5 100644
--- a/nixpkgs/nixos/modules/services/matrix/synapse.md
+++ b/nixpkgs/nixos/modules/services/matrix/synapse.md
@@ -126,8 +126,9 @@ then enable `services.matrix-synapse.settings.enable_registration = true;`.
 Otherwise, or you can generate a registration secret with
 {command}`pwgen -s 64 1` and set it with
 [](#opt-services.matrix-synapse.settings.registration_shared_secret).
-To create a new user or admin, run the following after you have set the secret
-and have rebuilt NixOS:
+To create a new user or admin from the terminal your client listener
+must be configured to use TCP sockets. Then you can run the following
+after you have set the secret and have rebuilt NixOS:
 ```ShellSession
 $ nix-shell -p matrix-synapse
 $ register_new_matrix_user -k your-registration-shared-secret http://localhost:8008
diff --git a/nixpkgs/nixos/modules/services/matrix/synapse.nix b/nixpkgs/nixos/modules/services/matrix/synapse.nix
index 50019d2a25cb..e3f9c7742cc7 100644
--- a/nixpkgs/nixos/modules/services/matrix/synapse.nix
+++ b/nixpkgs/nixos/modules/services/matrix/synapse.nix
@@ -6,8 +6,16 @@ let
   cfg = config.services.matrix-synapse;
   format = pkgs.formats.yaml { };
 
+  filterRecursiveNull = o:
+    if isAttrs o then
+      mapAttrs (_: v: filterRecursiveNull v) (filterAttrs (_: v: v != null) o)
+    else if isList o then
+      map filterRecursiveNull (filter (v: v != null) o)
+    else
+      o;
+
   # remove null values from the final configuration
-  finalSettings = lib.filterAttrsRecursive (_: v: v != null) cfg.settings;
+  finalSettings = filterRecursiveNull cfg.settings;
   configFile = format.generate "homeserver.yaml" finalSettings;
 
   usePostgresql = cfg.settings.database.name == "psycopg2";
@@ -105,6 +113,19 @@ let
         SYSLOG_IDENTIFIER = logName;
       };
     });
+
+  toIntBase8 = str:
+    lib.pipe str [
+      lib.stringToCharacters
+      (map lib.toInt)
+      (lib.foldl (acc: digit: acc * 8 + digit) 0)
+    ];
+
+  toDecimalFilePermission = value:
+    if value == null then
+      null
+    else
+      toIntBase8 value;
 in {
 
   imports = [
@@ -192,10 +213,11 @@ in {
   ];
 
   options = let
-    listenerType = workerContext: types.submodule {
+    listenerType = workerContext: types.submodule ({ config, ... }: {
       options = {
         port = mkOption {
-          type = types.port;
+          type = types.nullOr types.port;
+          default = null;
           example = 8448;
           description = lib.mdDoc ''
             The port to listen for HTTP(S) requests on.
@@ -203,11 +225,20 @@ in {
         };
 
         bind_addresses = mkOption {
-          type = types.listOf types.str;
-          default = [
+          type = types.nullOr (types.listOf types.str);
+          default = if config.path != null then null else [
             "::1"
             "127.0.0.1"
           ];
+          defaultText = literalExpression ''
+            if path != null then
+              null
+            else
+              [
+                "::1"
+                "127.0.0.1"
+              ]
+          '';
           example = literalExpression ''
             [
               "::"
@@ -219,6 +250,35 @@ in {
           '';
         };
 
+        path = mkOption {
+          type = types.nullOr types.path;
+          default = null;
+          description = ''
+            Unix domain socket path to bind this listener to.
+
+            ::: {.note}
+              This option is incompatible with {option}`bind_addresses`, {option}`port`, {option}`tls`
+              and also does not support the `metrics` and `manhole` listener {option}`type`.
+            :::
+          '';
+        };
+
+        mode = mkOption {
+          type = types.nullOr (types.strMatching "^[0,2-7]{3,4}$");
+          default = if config.path != null then "660" else null;
+          defaultText = literalExpression ''
+            if path != null then
+              "660"
+            else
+              null
+          '';
+          example = "660";
+          description = ''
+            File permissions on the UNIX domain socket.
+          '';
+          apply = toDecimalFilePermission;
+        };
+
         type = mkOption {
           type = types.enum [
             "http"
@@ -234,17 +294,30 @@ in {
         };
 
         tls = mkOption {
-          type = types.bool;
-          default = !workerContext;
+          type = types.nullOr types.bool;
+          default = if config.path != null then
+            null
+          else
+            !workerContext;
+          defaultText = ''
+            Enabled for the main instance listener, unless it is configured with a UNIX domain socket path.
+          '';
           example = false;
           description = lib.mdDoc ''
             Whether to enable TLS on the listener socket.
+
+            ::: {.note}
+              This option will be ignored for UNIX domain sockets.
+            :::
           '';
         };
 
         x_forwarded = mkOption {
           type = types.bool;
-          default = false;
+          default = config.path != null;
+          defaultText = ''
+            Enabled if the listener is configured with a UNIX domain socket path
+          '';
           example = true;
           description = lib.mdDoc ''
             Use the X-Forwarded-For (XFF) header as the client IP and not the
@@ -291,11 +364,28 @@ in {
           '';
         };
       };
-    };
+    });
   in {
     services.matrix-synapse = {
       enable = mkEnableOption (lib.mdDoc "matrix.org synapse");
 
+      enableRegistrationScript = mkOption {
+        type = types.bool;
+        default = clientListener.bind_addresses != [];
+        example = false;
+        defaultText = ''
+          Enabled if the client listener uses TCP sockets
+        '';
+        description = ''
+          Whether to install the `register_new_matrix_user` script, that
+          allows account creation on the terminal.
+
+          ::: {.note}
+            This script does not work when the client listener uses UNIX domain sockets
+          :::
+        '';
+      };
+
       serviceUnit = lib.mkOption {
         type = lib.types.str;
         readOnly = true;
@@ -616,11 +706,8 @@ in {
                   compress = false;
                 }];
               }] ++ lib.optional hasWorkers {
-                port = 9093;
-                bind_addresses = [ "127.0.0.1" ];
+                path = "/run/matrix-synapse/main_replication.sock";
                 type = "http";
-                tls = false;
-                x_forwarded = false;
                 resources = [{
                   names = [ "replication" ];
                   compress = false;
@@ -630,7 +717,7 @@ in {
                 List of ports that Synapse should listen on, their purpose and their configuration.
 
                 By default, synapse will be configured for client and federation traffic on port 8008, and
-                for worker replication traffic on port 9093. See [`services.matrix-synapse.workers`](#opt-services.matrix-synapse.workers)
+                use a UNIX domain socket for worker replication. See [`services.matrix-synapse.workers`](#opt-services.matrix-synapse.workers)
                 for more details.
               '';
             };
@@ -1006,9 +1093,15 @@ in {
             listener = lib.findFirst
               (
                 listener:
-                  listener.port == main.port
+                  (
+                    lib.hasAttr "port" main && listener.port or null == main.port
+                    || lib.hasAttr "path" main && listener.path or null == main.path
+                  )
                   && listenerSupportsResource "replication" listener
-                  && (lib.any (bind: bind == main.host || bind == "0.0.0.0" || bind == "::") listener.bind_addresses)
+                  && (
+                    lib.hasAttr "host" main &&  lib.any (bind: bind == main.host || bind == "0.0.0.0" || bind == "::") listener.bind_addresses
+                    || lib.hasAttr "path" main
+                  )
               )
               null
               cfg.settings.listeners;
@@ -1022,15 +1115,44 @@ in {
           This is done by default unless you manually configure either of those settings.
         '';
       }
-    ];
+      {
+        assertion = cfg.enableRegistrationScript -> clientListener.path == null;
+        message = ''
+          The client listener on matrix-synapse is configured to use UNIX domain sockets.
+          This configuration is incompatible with the `register_new_matrix_user` script.
+
+          Disable  `services.mastrix-synapse.enableRegistrationScript` to continue.
+        '';
+      }
+    ]
+    ++ (map (listener: {
+      assertion = (listener.path == null) != (listener.bind_addresses == null);
+      message = ''
+        Listeners require either a UNIX domain socket `path` or `bind_addresses` for a TCP socket.
+      '';
+    }) cfg.settings.listeners)
+    ++ (map (listener: {
+      assertion = listener.path != null -> (listener.bind_addresses == null && listener.port == null && listener.tls == null);
+      message = let
+        formatKeyValue = key: value: lib.optionalString (value != null) "  - ${key}=${toString value}\n";
+      in ''
+        Listener configured with UNIX domain socket (${toString listener.path}) ignores the following options:
+        ${formatKeyValue "bind_addresses" listener.bind_addresses}${formatKeyValue "port" listener.port}${formatKeyValue "tls" listener.tls}
+      '';
+    }) cfg.settings.listeners)
+    ++ (map (listener: {
+      assertion = listener.path == null || listener.type == "http";
+      message = ''
+        Listener configured with UNIX domain socket (${toString listener.path}) only supports the "http" listener type.
+      '';
+    }) cfg.settings.listeners);
 
     services.matrix-synapse.settings.redis = lib.mkIf cfg.configureRedisLocally {
       enabled = true;
       path = config.services.redis.servers.matrix-synapse.unixSocket;
     };
     services.matrix-synapse.settings.instance_map.main = lib.mkIf hasWorkers (lib.mkDefault {
-      host = "127.0.0.1";
-      port = 9093;
+      path = "/run/matrix-synapse/main_replication.sock";
     });
 
     services.matrix-synapse.serviceUnit = if hasWorkers then "matrix-synapse.target" else "matrix-synapse.service";
@@ -1056,6 +1178,7 @@ in {
 
     systemd.targets.matrix-synapse = lib.mkIf hasWorkers {
       description = "Synapse Matrix parent target";
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
       wantedBy = [ "multi-user.target" ];
     };
@@ -1071,6 +1194,7 @@ in {
             requires = optional hasLocalPostgresDB "postgresql.service";
           }
           else {
+            wants = [ "network-online.target" ];
             after = [ "network-online.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
             requires = optional hasLocalPostgresDB "postgresql.service";
             wantedBy = [ "multi-user.target" ];
@@ -1084,6 +1208,8 @@ in {
             User = "matrix-synapse";
             Group = "matrix-synapse";
             WorkingDirectory = cfg.dataDir;
+            RuntimeDirectory = "matrix-synapse";
+            RuntimeDirectoryPreserve = true;
             ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID";
             Restart = "on-failure";
             UMask = "0077";
@@ -1176,7 +1302,9 @@ in {
       user = "matrix-synapse";
     };
 
-    environment.systemPackages = [ registerNewMatrixUser ];
+    environment.systemPackages = lib.optionals cfg.enableRegistrationScript [
+      registerNewMatrixUser
+    ];
   };
 
   meta = {
diff --git a/nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix b/nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix
index 20b836abe164..89a1c0766510 100644
--- a/nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix
+++ b/nixpkgs/nixos/modules/services/misc/amazon-ssm-agent.nix
@@ -41,6 +41,7 @@ in {
     # See https://github.com/aws/amazon-ssm-agent/blob/mainline/packaging/linux/amazon-ssm-agent.service
     systemd.services.amazon-ssm-agent = {
       inherit (cfg.package.meta) description;
+      wants    = [ "network-online.target" ];
       after    = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
 
diff --git a/nixpkgs/nixos/modules/services/misc/bcg.nix b/nixpkgs/nixos/modules/services/misc/bcg.nix
index 9da4a879cdd0..ad0b9c871342 100644
--- a/nixpkgs/nixos/modules/services/misc/bcg.nix
+++ b/nixpkgs/nixos/modules/services/misc/bcg.nix
@@ -154,7 +154,7 @@ in
     in {
       description = "BigClown Gateway";
       wantedBy = [ "multi-user.target" ];
-      wants = mkIf config.services.mosquitto.enable [ "mosquitto.service" ];
+      wants = [ "network-online.target" ] ++ lib.optional config.services.mosquitto.enable "mosquitto.service";
       after = [ "network-online.target" ];
       preStart = ''
         umask 077
diff --git a/nixpkgs/nixos/modules/services/misc/domoticz.nix b/nixpkgs/nixos/modules/services/misc/domoticz.nix
index fd9fcf0b78eb..315092f93351 100644
--- a/nixpkgs/nixos/modules/services/misc/domoticz.nix
+++ b/nixpkgs/nixos/modules/services/misc/domoticz.nix
@@ -35,6 +35,7 @@ in {
     systemd.services."domoticz" = {
       description = pkgDesc;
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       serviceConfig = {
         DynamicUser = true;
diff --git a/nixpkgs/nixos/modules/services/misc/etesync-dav.nix b/nixpkgs/nixos/modules/services/misc/etesync-dav.nix
index 9d99d548d95b..ae2b5ad04343 100644
--- a/nixpkgs/nixos/modules/services/misc/etesync-dav.nix
+++ b/nixpkgs/nixos/modules/services/misc/etesync-dav.nix
@@ -59,6 +59,7 @@ in
 
       systemd.services.etesync-dav = {
         description = "etesync-dav - A CalDAV and CardDAV adapter for EteSync";
+        wants = [ "network-online.target" ];
         after = [ "network-online.target" ];
         wantedBy = [ "multi-user.target" ];
         path = [ pkgs.etesync-dav ];
diff --git a/nixpkgs/nixos/modules/services/misc/gitea.nix b/nixpkgs/nixos/modules/services/misc/gitea.nix
index d0135b2ba7ac..08feea853e47 100644
--- a/nixpkgs/nixos/modules/services/misc/gitea.nix
+++ b/nixpkgs/nixos/modules/services/misc/gitea.nix
@@ -681,6 +681,11 @@ in
       optional (cfg.database.password != "") "config.services.gitea.database.password will be stored as plaintext in the Nix store. Use database.passwordFile instead." ++
       optional (cfg.extraConfig != null) ''
         services.gitea.`extraConfig` is deprecated, please use services.gitea.`settings`.
+      '' ++
+      optional (lib.getName cfg.package == "forgejo") ''
+        Running forgejo via services.gitea.package is no longer supported.
+        Please use services.forgejo instead.
+        See https://nixos.org/manual/nixos/unstable/#module-forgejo for migration instructions.
       '';
 
     # Create database passwordFile default when password is configured.
diff --git a/nixpkgs/nixos/modules/services/misc/gitlab.nix b/nixpkgs/nixos/modules/services/misc/gitlab.nix
index 6756d59cf367..ec347a75f063 100644
--- a/nixpkgs/nixos/modules/services/misc/gitlab.nix
+++ b/nixpkgs/nixos/modules/services/misc/gitlab.nix
@@ -1386,10 +1386,8 @@ in {
 
     systemd.services.gitlab-db-config = {
       after = [ "gitlab-config.service" "gitlab-postgresql.service" "postgresql.service" ];
-      bindsTo = [
-        "gitlab-config.service"
-      ] ++ optional (cfg.databaseHost == "") "postgresql.service"
-        ++ optional databaseActuallyCreateLocally "gitlab-postgresql.service";
+      wants = optional (cfg.databaseHost == "") "postgresql.service" ++ optional databaseActuallyCreateLocally "gitlab-postgresql.service";
+      bindsTo = [ "gitlab-config.service" ];
       wantedBy = [ "gitlab.target" ];
       partOf = [ "gitlab.target" ];
       serviceConfig = {
@@ -1422,10 +1420,10 @@ in {
         "gitlab-db-config.service"
       ];
       bindsTo = [
-        "redis-gitlab.service"
         "gitlab-config.service"
         "gitlab-db-config.service"
-      ] ++ optional (cfg.databaseHost == "") "postgresql.service";
+      ];
+      wants = [ "redis-gitlab.service" ] ++ optional (cfg.databaseHost == "") "postgresql.service";
       wantedBy = [ "gitlab.target" ];
       partOf = [ "gitlab.target" ];
       environment = gitlabEnv // (optionalAttrs cfg.sidekiq.memoryKiller.enable {
@@ -1612,10 +1610,10 @@ in {
         "gitlab-db-config.service"
       ];
       bindsTo = [
-        "redis-gitlab.service"
         "gitlab-config.service"
         "gitlab-db-config.service"
-      ] ++ optional (cfg.databaseHost == "") "postgresql.service";
+      ];
+      wants = [ "redis-gitlab.service" ] ++ optional (cfg.databaseHost == "") "postgresql.service";
       requiredBy = [ "gitlab.target" ];
       partOf = [ "gitlab.target" ];
       environment = gitlabEnv;
diff --git a/nixpkgs/nixos/modules/services/misc/jellyfin.nix b/nixpkgs/nixos/modules/services/misc/jellyfin.nix
index 7042b491ffa4..a1d3910bd93b 100644
--- a/nixpkgs/nixos/modules/services/misc/jellyfin.nix
+++ b/nixpkgs/nixos/modules/services/misc/jellyfin.nix
@@ -1,109 +1,149 @@
 { config, pkgs, lib, ... }:
 
-with lib;
-
 let
+  inherit (lib) mkIf getExe maintainers mkEnableOption mkOption mkPackageOption;
+  inherit (lib.types) str path bool;
   cfg = config.services.jellyfin;
 in
 {
   options = {
     services.jellyfin = {
-      enable = mkEnableOption (lib.mdDoc "Jellyfin Media Server");
+      enable = mkEnableOption "Jellyfin Media Server";
+
+      package = mkPackageOption pkgs "jellyfin" { };
 
       user = mkOption {
-        type = types.str;
+        type = str;
         default = "jellyfin";
-        description = lib.mdDoc "User account under which Jellyfin runs.";
+        description = "User account under which Jellyfin runs.";
       };
 
-      package = mkPackageOption pkgs "jellyfin" { };
-
       group = mkOption {
-        type = types.str;
+        type = str;
         default = "jellyfin";
-        description = lib.mdDoc "Group under which jellyfin runs.";
+        description = "Group under which jellyfin runs.";
+      };
+
+      dataDir = mkOption {
+        type = path;
+        default = "/var/lib/jellyfin";
+        description = ''
+          Base data directory,
+          passed with `--datadir` see [#data-directory](https://jellyfin.org/docs/general/administration/configuration/#data-directory)
+        '';
+      };
+
+      configDir = mkOption {
+        type = path;
+        default = "${cfg.dataDir}/config";
+        defaultText = "\${cfg.dataDir}/config";
+        description = ''
+          Directory containing the server configuration files,
+          passed with `--configdir` see [configuration-directory](https://jellyfin.org/docs/general/administration/configuration/#configuration-directory)
+        '';
+      };
+
+      cacheDir = mkOption {
+        type = path;
+        default = "/var/cache/jellyfin";
+        description = ''
+          Directory containing the jellyfin server cache,
+          passed with `--cachedir` see [#cache-directory](https://jellyfin.org/docs/general/administration/configuration/#cache-directory)
+        '';
+      };
+
+      logDir = mkOption {
+        type = path;
+        default = "${cfg.dataDir}/log";
+        defaultText = "\${cfg.dataDir}/log";
+        description = ''
+          Directory where the Jellyfin logs will be stored,
+          passed with `--logdir` see [#log-directory](https://jellyfin.org/docs/general/administration/configuration/#log-directory)
+        '';
       };
 
       openFirewall = mkOption {
-        type = types.bool;
+        type = bool;
         default = false;
-        description = lib.mdDoc ''
+        description = ''
           Open the default ports in the firewall for the media server. The
           HTTP/HTTPS ports can be changed in the Web UI, so this option should
-          only be used if they are unchanged.
+          only be used if they are unchanged, see [Port Bindings](https://jellyfin.org/docs/general/networking/#port-bindings).
         '';
       };
     };
   };
 
   config = mkIf cfg.enable {
-    systemd.services.jellyfin = {
-      description = "Jellyfin Media Server";
-      after = [ "network-online.target" ];
-      wants = [ "network-online.target" ];
-      wantedBy = [ "multi-user.target" ];
-
-      # This is mostly follows: https://github.com/jellyfin/jellyfin/blob/master/fedora/jellyfin.service
-      # Upstream also disable some hardenings when running in LXC, we do the same with the isContainer option
-      serviceConfig = rec {
-        Type = "simple";
-        User = cfg.user;
-        Group = cfg.group;
-        StateDirectory = "jellyfin";
-        StateDirectoryMode = "0700";
-        CacheDirectory = "jellyfin";
-        CacheDirectoryMode = "0700";
-        UMask = "0077";
-        WorkingDirectory = "/var/lib/jellyfin";
-        ExecStart = "${cfg.package}/bin/jellyfin --datadir '/var/lib/${StateDirectory}' --cachedir '/var/cache/${CacheDirectory}'";
-        Restart = "on-failure";
-        TimeoutSec = 15;
-        SuccessExitStatus = ["0" "143"];
-
-        # Security options:
-        NoNewPrivileges = true;
-        SystemCallArchitectures = "native";
-        # AF_NETLINK needed because Jellyfin monitors the network connection
-        RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ];
-        RestrictNamespaces = !config.boot.isContainer;
-        RestrictRealtime = true;
-        RestrictSUIDSGID = true;
-        ProtectControlGroups = !config.boot.isContainer;
-        ProtectHostname = true;
-        ProtectKernelLogs = !config.boot.isContainer;
-        ProtectKernelModules = !config.boot.isContainer;
-        ProtectKernelTunables = !config.boot.isContainer;
-        LockPersonality = true;
-        PrivateTmp = !config.boot.isContainer;
-        # needed for hardware acceleration
-        PrivateDevices = false;
-        PrivateUsers = true;
-        RemoveIPC = true;
-
-        SystemCallFilter = [
-          "~@clock"
-          "~@aio"
-          "~@chown"
-          "~@cpu-emulation"
-          "~@debug"
-          "~@keyring"
-          "~@memlock"
-          "~@module"
-          "~@mount"
-          "~@obsolete"
-          "~@privileged"
-          "~@raw-io"
-          "~@reboot"
-          "~@setuid"
-          "~@swap"
-        ];
-        SystemCallErrorNumber = "EPERM";
+    systemd = {
+      tmpfiles.settings.jellyfinDirs = {
+        "${cfg.dataDir}"."d" = {
+          mode = "700";
+          inherit (cfg) user group;
+        };
+        "${cfg.configDir}"."d" = {
+          mode = "700";
+          inherit (cfg) user group;
+        };
+        "${cfg.logDir}"."d" = {
+          mode = "700";
+          inherit (cfg) user group;
+        };
+        "${cfg.cacheDir}"."d" = {
+          mode = "700";
+          inherit (cfg) user group;
+        };
+      };
+      services.jellyfin = {
+        description = "Jellyfin Media Server";
+        after = [ "network-online.target" ];
+        wants = [ "network-online.target" ];
+        wantedBy = [ "multi-user.target" ];
+
+        # This is mostly follows: https://github.com/jellyfin/jellyfin/blob/master/fedora/jellyfin.service
+        # Upstream also disable some hardenings when running in LXC, we do the same with the isContainer option
+        serviceConfig = {
+          Type = "simple";
+          User = cfg.user;
+          Group = cfg.group;
+          UMask = "0077";
+          WorkingDirectory = cfg.dataDir;
+          ExecStart = "${getExe cfg.package} --datadir '${cfg.dataDir}' --configdir '${cfg.configDir}' --cachedir '${cfg.cacheDir}' --logdir '${cfg.logDir}'";
+          Restart = "on-failure";
+          TimeoutSec = 15;
+          SuccessExitStatus = ["0" "143"];
+
+          # Security options:
+          NoNewPrivileges = true;
+          SystemCallArchitectures = "native";
+          # AF_NETLINK needed because Jellyfin monitors the network connection
+          RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ];
+          RestrictNamespaces = !config.boot.isContainer;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+          ProtectControlGroups = !config.boot.isContainer;
+          ProtectHostname = true;
+          ProtectKernelLogs = !config.boot.isContainer;
+          ProtectKernelModules = !config.boot.isContainer;
+          ProtectKernelTunables = !config.boot.isContainer;
+          LockPersonality = true;
+          PrivateTmp = !config.boot.isContainer;
+          # needed for hardware acceleration
+          PrivateDevices = false;
+          PrivateUsers = true;
+          RemoveIPC = true;
+
+          SystemCallFilter = [
+            "~@clock" "~@aio" "~@chown" "~@cpu-emulation" "~@debug" "~@keyring" "~@memlock" "~@module" "~@mount" "~@obsolete" "~@privileged" "~@raw-io" "~@reboot" "~@setuid" "~@swap"
+          ];
+          SystemCallErrorNumber = "EPERM";
+        };
       };
     };
 
     users.users = mkIf (cfg.user == "jellyfin") {
       jellyfin = {
-        group = cfg.group;
+        inherit (cfg) group;
         isSystemUser = true;
       };
     };
@@ -120,5 +160,5 @@ in
 
   };
 
-  meta.maintainers = with lib.maintainers; [ minijackson ];
+  meta.maintainers = with maintainers; [ minijackson nu-nu-ko ];
 }
diff --git a/nixpkgs/nixos/modules/services/misc/lidarr.nix b/nixpkgs/nixos/modules/services/misc/lidarr.nix
index 4dc0fc63863b..8ceb567e8801 100644
--- a/nixpkgs/nixos/modules/services/misc/lidarr.nix
+++ b/nixpkgs/nixos/modules/services/misc/lidarr.nix
@@ -45,9 +45,10 @@ in
   };
 
   config = mkIf cfg.enable {
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
-    ];
+    systemd.tmpfiles.settings."10-lidarr".${cfg.dataDir}.d = {
+      inherit (cfg) user group;
+      mode = "0700";
+    };
 
     systemd.services.lidarr = {
       description = "Lidarr";
diff --git a/nixpkgs/nixos/modules/services/misc/mediatomb.nix b/nixpkgs/nixos/modules/services/misc/mediatomb.nix
index d421d74c53ad..03235e9a1265 100644
--- a/nixpkgs/nixos/modules/services/misc/mediatomb.nix
+++ b/nixpkgs/nixos/modules/services/misc/mediatomb.nix
@@ -357,6 +357,7 @@ in {
       description = "${cfg.serverName} media Server";
       # Gerbera might fail if the network interface is not available on startup
       # https://github.com/gerbera/gerbera/issues/1324
+      wants = [ "network-online.target" ];
       after = [ "network.target" "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
       serviceConfig.ExecStart = "${binaryCommand} --port ${toString cfg.port} ${interfaceFlag} ${configFlag} --home ${cfg.dataDir}";
diff --git a/nixpkgs/nixos/modules/services/misc/metabase.nix b/nixpkgs/nixos/modules/services/misc/metabase.nix
index 883fa0b95911..5fc18e27eaae 100644
--- a/nixpkgs/nixos/modules/services/misc/metabase.nix
+++ b/nixpkgs/nixos/modules/services/misc/metabase.nix
@@ -77,6 +77,7 @@ in {
     systemd.services.metabase = {
       description = "Metabase server";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       environment = {
         MB_PLUGINS_DIR = "${dataDir}/plugins";
diff --git a/nixpkgs/nixos/modules/services/misc/moonraker.nix b/nixpkgs/nixos/modules/services/misc/moonraker.nix
index 750dca9d0373..f043cc83bf05 100644
--- a/nixpkgs/nixos/modules/services/misc/moonraker.nix
+++ b/nixpkgs/nixos/modules/services/misc/moonraker.nix
@@ -103,17 +103,18 @@ in {
 
   config = mkIf cfg.enable {
     warnings = []
-      ++ optional (cfg.settings ? update_manager)
-        ''Enabling update_manager is not supported on NixOS and will lead to non-removable warnings in some clients.''
-      ++ optional (cfg.configDir != null)
-        ''
-          services.moonraker.configDir has been deprecated upstream and will be removed.
-
-          Action: ${
-            if cfg.configDir == unifiedConfigDir then "Simply remove services.moonraker.configDir from your config."
-            else "Move files from `${cfg.configDir}` to `${unifiedConfigDir}` then remove services.moonraker.configDir from your config."
-          }
-        '';
+      ++ (optional (head (cfg.settings.update_manager.enable_system_updates or [false])) ''
+        Enabling system updates is not supported on NixOS and will lead to non-removable warnings in some clients.
+      '')
+      ++ (optional (cfg.configDir != null) ''
+        services.moonraker.configDir has been deprecated upstream and will be removed.
+
+        Action: ${
+          if cfg.configDir == unifiedConfigDir
+          then "Simply remove services.moonraker.configDir from your config."
+          else "Move files from `${cfg.configDir}` to `${unifiedConfigDir}` then remove services.moonraker.configDir from your config."
+        }
+        '');
 
     assertions = [
       {
diff --git a/nixpkgs/nixos/modules/services/misc/nix-gc.nix b/nixpkgs/nixos/modules/services/misc/nix-gc.nix
index 97596d28cd89..656cbad81373 100644
--- a/nixpkgs/nixos/modules/services/misc/nix-gc.nix
+++ b/nixpkgs/nixos/modules/services/misc/nix-gc.nix
@@ -1,7 +1,5 @@
 { config, lib, ... }:
 
-with lib;
-
 let
   cfg = config.nix.gc;
 in
@@ -14,14 +12,14 @@ in
 
     nix.gc = {
 
-      automatic = mkOption {
+      automatic = lib.mkOption {
         default = false;
-        type = types.bool;
+        type = lib.types.bool;
         description = lib.mdDoc "Automatically run the garbage collector at a specific time.";
       };
 
-      dates = mkOption {
-        type = types.str;
+      dates = lib.mkOption {
+        type = lib.types.singleLineStr;
         default = "03:15";
         example = "weekly";
         description = lib.mdDoc ''
@@ -33,9 +31,9 @@ in
         '';
       };
 
-      randomizedDelaySec = mkOption {
+      randomizedDelaySec = lib.mkOption {
         default = "0";
-        type = types.str;
+        type = lib.types.singleLineStr;
         example = "45min";
         description = lib.mdDoc ''
           Add a randomized delay before each garbage collection.
@@ -45,9 +43,9 @@ in
         '';
       };
 
-      persistent = mkOption {
+      persistent = lib.mkOption {
         default = true;
-        type = types.bool;
+        type = lib.types.bool;
         example = false;
         description = lib.mdDoc ''
           Takes a boolean argument. If true, the time when the service
@@ -61,13 +59,12 @@ in
         '';
       };
 
-      options = mkOption {
+      options = lib.mkOption {
         default = "";
         example = "--max-freed $((64 * 1024**3))";
-        type = types.str;
+        type = lib.types.singleLineStr;
         description = lib.mdDoc ''
-          Options given to {file}`nix-collect-garbage` when the
-          garbage collector is run automatically.
+          Options given to [`nix-collect-garbage`](https://nixos.org/manual/nix/stable/command-ref/nix-collect-garbage) when the garbage collector is run automatically.
         '';
       };
 
@@ -89,7 +86,8 @@ in
     systemd.services.nix-gc = lib.mkIf config.nix.enable {
       description = "Nix Garbage Collector";
       script = "exec ${config.nix.package.out}/bin/nix-collect-garbage ${cfg.options}";
-      startAt = optional cfg.automatic cfg.dates;
+      serviceConfig.Type = "oneshot";
+      startAt = lib.optional cfg.automatic cfg.dates;
     };
 
     systemd.timers.nix-gc = lib.mkIf cfg.automatic {
diff --git a/nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix b/nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix
index b656692ca01c..cf9d6339c69b 100644
--- a/nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix
+++ b/nixpkgs/nixos/modules/services/misc/nix-ssh-serve.nix
@@ -1,4 +1,4 @@
-{ config, lib, ... }:
+{ config, lib, pkgs, ... }:
 
 with lib;
 let cfg = config.nix.sshServe;
@@ -46,7 +46,7 @@ in {
       description = "Nix SSH store user";
       isSystemUser = true;
       group = "nix-ssh";
-      useDefaultShell = true;
+      shell = pkgs.bashInteractive;
     };
     users.groups.nix-ssh = {};
 
diff --git a/nixpkgs/nixos/modules/services/misc/ollama.nix b/nixpkgs/nixos/modules/services/misc/ollama.nix
index 9794bbbec464..d9359d2b5cd4 100644
--- a/nixpkgs/nixos/modules/services/misc/ollama.nix
+++ b/nixpkgs/nixos/modules/services/misc/ollama.nix
@@ -9,6 +9,13 @@ in {
       enable = lib.mkEnableOption (
         lib.mdDoc "Server for local large language models"
       );
+      listenAddress = lib.mkOption {
+        type = lib.types.str;
+        default = "127.0.0.1:11434";
+        description = lib.mdDoc ''
+          Specifies the bind address on which the ollama server HTTP interface listens.
+        '';
+      };
       package = lib.mkPackageOption pkgs "ollama" { };
     };
   };
@@ -23,6 +30,7 @@ in {
         environment = {
           HOME = "%S/ollama";
           OLLAMA_MODELS = "%S/ollama/models";
+          OLLAMA_HOST = cfg.listenAddress;
         };
         serviceConfig = {
           ExecStart = "${lib.getExe cfg.package} serve";
diff --git a/nixpkgs/nixos/modules/services/misc/packagekit.nix b/nixpkgs/nixos/modules/services/misc/packagekit.nix
index 5a0d314d25cd..f4191a4453ca 100644
--- a/nixpkgs/nixos/modules/services/misc/packagekit.nix
+++ b/nixpkgs/nixos/modules/services/misc/packagekit.nix
@@ -13,7 +13,7 @@ let
     (iniFmt.generate "PackageKit.conf" (recursiveUpdate
       {
         Daemon = {
-          DefaultBackend = "nix";
+          DefaultBackend = "test_nop";
           KeepCache = false;
         };
       }
@@ -35,7 +35,7 @@ let
 in
 {
   imports = [
-    (mkRemovedOptionModule [ "services" "packagekit" "backend" ] "Always set to Nix.")
+    (mkRemovedOptionModule [ "services" "packagekit" "backend" ] "Always set to test_nop, Nix backend is broken see #177946.")
   ];
 
   options.services.packagekit = {
diff --git a/nixpkgs/nixos/modules/services/misc/paperless.nix b/nixpkgs/nixos/modules/services/misc/paperless.nix
index 3c6832958f59..1256d8315c8b 100644
--- a/nixpkgs/nixos/modules/services/misc/paperless.nix
+++ b/nixpkgs/nixos/modules/services/misc/paperless.nix
@@ -6,7 +6,6 @@ let
   pkg = cfg.package;
 
   defaultUser = "paperless";
-  nltkDir = "/var/cache/paperless/nltk";
   defaultFont = "${pkgs.liberation_ttf}/share/fonts/truetype/LiberationSerif-Regular.ttf";
 
   # Don't start a redis instance if the user sets a custom redis connection
@@ -17,13 +16,17 @@ let
     PAPERLESS_DATA_DIR = cfg.dataDir;
     PAPERLESS_MEDIA_ROOT = cfg.mediaDir;
     PAPERLESS_CONSUMPTION_DIR = cfg.consumptionDir;
-    PAPERLESS_NLTK_DIR = nltkDir;
     PAPERLESS_THUMBNAIL_FONT_NAME = defaultFont;
     GUNICORN_CMD_ARGS = "--bind=${cfg.address}:${toString cfg.port}";
   } // optionalAttrs (config.time.timeZone != null) {
     PAPERLESS_TIME_ZONE = config.time.timeZone;
   } // optionalAttrs enableRedis {
     PAPERLESS_REDIS = "unix://${redisServer.unixSocket}";
+  } // optionalAttrs (cfg.settings.PAPERLESS_ENABLE_NLTK or true) {
+    PAPERLESS_NLTK_DIR = pkgs.symlinkJoin {
+      name = "paperless_ngx_nltk_data";
+      paths = pkg.nltkData;
+    };
   } // (lib.mapAttrs (_: s:
     if (lib.isAttrs s || lib.isList s) then builtins.toJSON s
     else if lib.isBool s then lib.boolToString s
@@ -141,12 +144,12 @@ in
         `''${dataDir}/paperless-manage createsuperuser`.
 
         The default superuser name is `admin`. To change it, set
-        option {option}`extraConfig.PAPERLESS_ADMIN_USER`.
+        option {option}`settings.PAPERLESS_ADMIN_USER`.
         WARNING: When changing the superuser name after the initial setup, the old superuser
         will continue to exist.
 
         To disable login for the web interface, set the following:
-        `extraConfig.PAPERLESS_AUTO_LOGIN_USERNAME = "admin";`.
+        `settings.PAPERLESS_AUTO_LOGIN_USERNAME = "admin";`.
         WARNING: Only use this on a trusted system without internet access to Paperless.
       '';
     };
@@ -292,22 +295,6 @@ in
       };
     };
 
-    # Download NLTK corpus data
-    systemd.services.paperless-download-nltk-data = {
-      wantedBy = [ "paperless-scheduler.service" ];
-      before = [ "paperless-scheduler.service" ];
-      after = [ "network-online.target" ];
-      serviceConfig = defaultServiceConfig // {
-        User = cfg.user;
-        Type = "oneshot";
-        # Enable internet access
-        PrivateNetwork = false;
-        ExecStart = let pythonWithNltk = pkg.python.withPackages (ps: [ ps.nltk ]); in ''
-          ${pythonWithNltk}/bin/python -m nltk.downloader -d '${nltkDir}' punkt snowball_data stopwords
-        '';
-      };
-    };
-
     systemd.services.paperless-consumer = {
       description = "Paperless document consumer";
       # Bind to `paperless-scheduler` so that the consumer never runs
diff --git a/nixpkgs/nixos/modules/services/misc/portunus.nix b/nixpkgs/nixos/modules/services/misc/portunus.nix
index 7036a372d1ea..ebb3bc8f0851 100644
--- a/nixpkgs/nixos/modules/services/misc/portunus.nix
+++ b/nixpkgs/nixos/modules/services/misc/portunus.nix
@@ -37,6 +37,15 @@ in
       '';
     };
 
+    seedSettings = lib.mkOption {
+      type = with lib.types; nullOr (attrsOf (listOf (attrsOf anything)));
+      default = null;
+      description = lib.mdDoc ''
+        Seed settings for users and groups.
+        See upstream for format <https://github.com/majewsky/portunus#seeding-users-and-groups-from-static-configuration>
+      '';
+    };
+
     stateDir = mkOption {
       type = types.path;
       default = "/var/lib/portunus";
@@ -172,49 +181,53 @@ in
       "127.0.0.1" = [ cfg.domain ];
     };
 
-    services.dex = mkIf cfg.dex.enable {
-      enable = true;
-      settings = {
-        issuer = "https://${cfg.domain}/dex";
-        web.http = "127.0.0.1:${toString cfg.dex.port}";
-        storage = {
-          type = "sqlite3";
-          config.file = "/var/lib/dex/dex.db";
-        };
-        enablePasswordDB = false;
-        connectors = [{
-          type = "ldap";
-          id = "ldap";
-          name = "LDAP";
-          config = {
-            host = "${cfg.domain}:636";
-            bindDN = "uid=${cfg.ldap.searchUserName},ou=users,${cfg.ldap.suffix}";
-            bindPW = "$DEX_SEARCH_USER_PASSWORD";
-            userSearch = {
-              baseDN = "ou=users,${cfg.ldap.suffix}";
-              filter = "(objectclass=person)";
-              username = "uid";
-              idAttr = "uid";
-              emailAttr = "mail";
-              nameAttr = "cn";
-              preferredUsernameAttr = "uid";
-            };
-            groupSearch = {
-              baseDN = "ou=groups,${cfg.ldap.suffix}";
-              filter = "(objectclass=groupOfNames)";
-              nameAttr = "cn";
-              userMatchers = [{ userAttr = "DN"; groupAttr = "member"; }];
-            };
+    services = {
+      dex = mkIf cfg.dex.enable {
+        enable = true;
+        settings = {
+          issuer = "https://${cfg.domain}/dex";
+          web.http = "127.0.0.1:${toString cfg.dex.port}";
+          storage = {
+            type = "sqlite3";
+            config.file = "/var/lib/dex/dex.db";
           };
-        }];
-
-        staticClients = forEach cfg.dex.oidcClients (client: {
-          inherit (client) id;
-          redirectURIs = [ client.callbackURL ];
-          name = "OIDC for ${client.id}";
-          secretEnv = "DEX_CLIENT_${client.id}";
-        });
+          enablePasswordDB = false;
+          connectors = [{
+            type = "ldap";
+            id = "ldap";
+            name = "LDAP";
+            config = {
+              host = "${cfg.domain}:636";
+              bindDN = "uid=${cfg.ldap.searchUserName},ou=users,${cfg.ldap.suffix}";
+              bindPW = "$DEX_SEARCH_USER_PASSWORD";
+              userSearch = {
+                baseDN = "ou=users,${cfg.ldap.suffix}";
+                filter = "(objectclass=person)";
+                username = "uid";
+                idAttr = "uid";
+                emailAttr = "mail";
+                nameAttr = "cn";
+                preferredUsernameAttr = "uid";
+              };
+              groupSearch = {
+                baseDN = "ou=groups,${cfg.ldap.suffix}";
+                filter = "(objectclass=groupOfNames)";
+                nameAttr = "cn";
+                userMatchers = [{ userAttr = "DN"; groupAttr = "member"; }];
+              };
+            };
+          }];
+
+          staticClients = forEach cfg.dex.oidcClients (client: {
+            inherit (client) id;
+            redirectURIs = [ client.callbackURL ];
+            name = "OIDC for ${client.id}";
+            secretEnv = "DEX_CLIENT_${client.id}";
+          });
+        };
       };
+
+      portunus.seedPath = lib.mkIf (cfg.seedSettings != null) (pkgs.writeText "seed.json" (builtins.toJSON cfg.seedSettings));
     };
 
     systemd.services = {
@@ -230,7 +243,10 @@ in
         description = "Self-contained authentication service";
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" ];
-        serviceConfig.ExecStart = "${cfg.package.out}/bin/portunus-orchestrator";
+        serviceConfig = {
+          ExecStart = "${cfg.package}/bin/portunus-orchestrator";
+          Restart = "on-failure";
+        };
         environment = {
           PORTUNUS_LDAP_SUFFIX = cfg.ldap.suffix;
           PORTUNUS_SERVER_BINARY = "${cfg.package}/bin/portunus-server";
diff --git a/nixpkgs/nixos/modules/services/misc/radarr.nix b/nixpkgs/nixos/modules/services/misc/radarr.nix
index 618341cf614f..a5f264331ed3 100644
--- a/nixpkgs/nixos/modules/services/misc/radarr.nix
+++ b/nixpkgs/nixos/modules/services/misc/radarr.nix
@@ -40,9 +40,10 @@ in
   };
 
   config = mkIf cfg.enable {
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
-    ];
+    systemd.tmpfiles.settings."10-radarr".${cfg.dataDir}.d = {
+      inherit (cfg) user group;
+      mode = "0700";
+    };
 
     systemd.services.radarr = {
       description = "Radarr";
diff --git a/nixpkgs/nixos/modules/services/misc/readarr.nix b/nixpkgs/nixos/modules/services/misc/readarr.nix
index 3c84b13485a4..73868b4baa95 100644
--- a/nixpkgs/nixos/modules/services/misc/readarr.nix
+++ b/nixpkgs/nixos/modules/services/misc/readarr.nix
@@ -45,9 +45,10 @@ in
   };
 
   config = mkIf cfg.enable {
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
-    ];
+    systemd.tmpfiles.settings."10-readarr".${cfg.dataDir}.d = {
+      inherit (cfg) user group;
+      mode = "0700";
+    };
 
     systemd.services.readarr = {
       description = "Readarr";
diff --git a/nixpkgs/nixos/modules/services/misc/sourcehut/default.nix b/nixpkgs/nixos/modules/services/misc/sourcehut/default.nix
index aa803d3bb693..80a6162b2168 100644
--- a/nixpkgs/nixos/modules/services/misc/sourcehut/default.nix
+++ b/nixpkgs/nixos/modules/services/misc/sourcehut/default.nix
@@ -1370,5 +1370,5 @@ in
   ];
 
   meta.doc = ./default.md;
-  meta.maintainers = with maintainers; [ tomberek nessdoor ];
+  meta.maintainers = with maintainers; [ tomberek nessdoor christoph-heiss ];
 }
diff --git a/nixpkgs/nixos/modules/services/misc/taskserver/helper-tool.py b/nixpkgs/nixos/modules/services/misc/taskserver/helper-tool.py
index fec05728b2b6..b1eebb07686b 100644
--- a/nixpkgs/nixos/modules/services/misc/taskserver/helper-tool.py
+++ b/nixpkgs/nixos/modules/services/misc/taskserver/helper-tool.py
@@ -61,6 +61,10 @@ def run_as_taskd_user():
     os.setuid(uid)
 
 
+def run_as_taskd_group():
+    gid = grp.getgrnam(TASKD_GROUP).gr_gid
+    os.setgid(gid)
+
 def taskd_cmd(cmd, *args, **kwargs):
     """
     Invoke taskd with the specified command with the privileges of the 'taskd'
@@ -90,7 +94,7 @@ def certtool_cmd(*args, **kwargs):
     """
     return subprocess.check_output(
         [CERTTOOL_COMMAND] + list(args),
-        preexec_fn=lambda: os.umask(0o077),
+        preexec_fn=run_as_taskd_group,
         stderr=subprocess.STDOUT,
         **kwargs
     )
@@ -156,17 +160,33 @@ def generate_key(org, user):
         sys.stderr.write(msg.format(user))
         return
 
-    basedir = os.path.join(TASKD_DATA_DIR, "keys", org, user)
-    if os.path.exists(basedir):
+    keysdir = os.path.join(TASKD_DATA_DIR, "keys" )
+    orgdir  = os.path.join(keysdir       , org    )
+    userdir = os.path.join(orgdir        , user   )
+    if os.path.exists(userdir):
         raise OSError("Keyfile directory for {} already exists.".format(user))
 
-    privkey = os.path.join(basedir, "private.key")
-    pubcert = os.path.join(basedir, "public.cert")
+    privkey = os.path.join(userdir, "private.key")
+    pubcert = os.path.join(userdir, "public.cert")
 
     try:
-        os.makedirs(basedir, mode=0o700)
+        # We change the permissions and the owner ship of the base directories
+        # so that cfg.group and cfg.user could read the directories' contents.
+        # See also: https://bugs.python.org/issue42367
+        for bd in [keysdir, orgdir, userdir]:
+            # Allow cfg.group, but not others to read the contents of this group
+            os.makedirs(bd, exist_ok=True)
+            # not using mode= argument to makedirs intentionally - forcing the
+            # permissions we want
+            os.chmod(bd, mode=0o750)
+            os.chown(
+                bd,
+                uid=pwd.getpwnam(TASKD_USER).pw_uid,
+                gid=grp.getgrnam(TASKD_GROUP).gr_gid,
+            )
 
         certtool_cmd("-p", "--bits", CERT_BITS, "--outfile", privkey)
+        os.chmod(privkey, 0o640)
 
         template_data = [
             "organization = {0}".format(org),
@@ -187,7 +207,7 @@ def generate_key(org, user):
                 "--outfile", pubcert
             )
     except:
-        rmtree(basedir)
+        rmtree(userdir)
         raise
 
 
diff --git a/nixpkgs/nixos/modules/services/monitoring/alerta.nix b/nixpkgs/nixos/modules/services/monitoring/alerta.nix
index 6c7ebec4191c..0b0ab177e5e1 100644
--- a/nixpkgs/nixos/modules/services/monitoring/alerta.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/alerta.nix
@@ -79,9 +79,10 @@ in
   };
 
   config = mkIf cfg.enable {
-    systemd.tmpfiles.rules = [
-      "d '${cfg.logDir}' - alerta alerta - -"
-    ];
+    systemd.tmpfiles.settings."10-alerta".${cfg.logDir}.d = {
+      user = "alerta";
+      group = "alerta";
+    };
 
     systemd.services.alerta = {
       description = "Alerta Monitoring System";
diff --git a/nixpkgs/nixos/modules/services/monitoring/kapacitor.nix b/nixpkgs/nixos/modules/services/monitoring/kapacitor.nix
index 727b694047b4..c90878656899 100644
--- a/nixpkgs/nixos/modules/services/monitoring/kapacitor.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/kapacitor.nix
@@ -160,9 +160,9 @@ in
   config = mkIf cfg.enable {
     environment.systemPackages = [ pkgs.kapacitor ];
 
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' - ${cfg.user} ${cfg.group} - -"
-    ];
+    systemd.tmpfiles.settings."10-kapacitor".${cfg.dataDir}.d = {
+      inherit (cfg) user group;
+    };
 
     systemd.services.kapacitor = {
       description = "Kapacitor Real-Time Stream Processing Engine";
diff --git a/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix b/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix
index 62a7858500f2..5915634ed26f 100644
--- a/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix
@@ -84,6 +84,7 @@ in {
     # upstream service file in https://git.io/JUt4Q
     systemd.services.mackerel-agent = {
       description = "mackerel.io agent";
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" "nss-lookup.target" ];
       wantedBy = [ "multi-user.target" ];
       environment = {
diff --git a/nixpkgs/nixos/modules/services/monitoring/munin.nix b/nixpkgs/nixos/modules/services/monitoring/munin.nix
index 5ed7cac48ae7..456a14169b95 100644
--- a/nixpkgs/nixos/modules/services/monitoring/munin.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/munin.nix
@@ -374,7 +374,11 @@ in
     };
 
     # munin_stats plugin breaks as of 2.0.33 when this doesn't exist
-    systemd.tmpfiles.rules = [ "d /run/munin 0755 munin munin -" ];
+    systemd.tmpfiles.settings."10-munin"."/run/munin".d = {
+      mode = "0755";
+      user = "munin";
+      group = "munin";
+    };
 
   }) (mkIf cronCfg.enable {
 
@@ -399,11 +403,17 @@ in
       };
     };
 
-    systemd.tmpfiles.rules = [
-      "d /run/munin 0755 munin munin -"
-      "d /var/log/munin 0755 munin munin -"
-      "d /var/www/munin 0755 munin munin -"
-      "d /var/lib/munin 0755 munin munin -"
-    ];
+    systemd.tmpfiles.settings."20-munin" = let
+      defaultConfig = {
+        mode = "0755";
+        user = "munin";
+        group = "munin";
+      };
+    in {
+      "/run/munin".d = defaultConfig;
+      "/var/log/munin".d = defaultConfig;
+      "/var/www/munin".d = defaultConfig;
+      "/var/lib/munin".d = defaultConfig;
+    };
   })];
 }
diff --git a/nixpkgs/nixos/modules/services/monitoring/osquery.nix b/nixpkgs/nixos/modules/services/monitoring/osquery.nix
index 4f6c2557a641..86ef3fc73213 100644
--- a/nixpkgs/nixos/modules/services/monitoring/osquery.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/osquery.nix
@@ -90,8 +90,10 @@ in
       };
       wantedBy = [ "multi-user.target" ];
     };
-    systemd.tmpfiles.rules = [
-      "d ${dirname (cfg.flags.pidfile)} 0755 root root -"
-    ];
+    systemd.tmpfiles.settings."10-osquery".${dirname (cfg.flags.pidfile)}.d = {
+      user = "root";
+      group = "root";
+      mode = "0755";
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/alertmanager.nix
index 4fd630015f35..bb426d8b7beb 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/alertmanager.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/alertmanager.nix
@@ -174,6 +174,7 @@ in {
 
       systemd.services.alertmanager = {
         wantedBy = [ "multi-user.target" ];
+        wants    = [ "network-online.target" ];
         after    = [ "network-online.target" ];
         preStart = ''
            ${lib.getBin pkgs.envsubst}/bin/envsubst -o "/tmp/alert-manager-substituted.yaml" \
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
index 35db8a7376b1..6be6ba7edf72 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -60,7 +60,6 @@ let
     "node"
     "nut"
     "openldap"
-    "openvpn"
     "pgbouncer"
     "php-fpm"
     "pihole"
@@ -71,6 +70,7 @@ let
     "pve"
     "py-air-control"
     "redis"
+    "restic"
     "rspamd"
     "rtl_433"
     "sabnzbd"
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix
deleted file mode 100644
index 5b54dad99805..000000000000
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix
+++ /dev/null
@@ -1,39 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-with lib;
-
-let
-  cfg = config.services.prometheus.exporters.openvpn;
-in {
-  port = 9176;
-  extraOpts = {
-    statusPaths = mkOption {
-      type = types.listOf types.str;
-      description = lib.mdDoc ''
-        Paths to OpenVPN status files. Please configure the OpenVPN option
-        `status` accordingly.
-      '';
-    };
-    telemetryPath = mkOption {
-      type = types.str;
-      default = "/metrics";
-      description = lib.mdDoc ''
-        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/pve.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix
index 20ee2e4b3238..83e740320df2 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix
@@ -21,7 +21,7 @@ in
       type = with types; nullOr path;
       default = null;
       example = "/etc/prometheus-pve-exporter/pve.env";
-      description = lib.mdDoc ''
+      description = ''
         Path to the service's environment file. This path can either be a computed path in /nix/store or a path in the local filesystem.
 
         The environment file should NOT be stored in /nix/store as it contains passwords and/or keys in plain text.
@@ -34,7 +34,7 @@ in
       type = with types; nullOr path;
       default = null;
       example = "/etc/prometheus-pve-exporter/pve.yml";
-      description = lib.mdDoc ''
+      description = ''
         Path to the service's config file. This path can either be a computed path in /nix/store or a path in the local filesystem.
 
         The config file should NOT be stored in /nix/store as it will contain passwords and/or keys in plain text.
@@ -45,46 +45,66 @@ in
       '';
     };
 
+    server = {
+      keyFile = mkOption {
+        type = with types; nullOr path;
+        default = null;
+        example = "/var/lib/prometheus-pve-exporter/privkey.key";
+        description = ''
+          Path to a SSL private key file for the server
+        '';
+      };
+
+      certFile = mkOption {
+        type = with types; nullOr path;
+        default = null;
+        example = "/var/lib/prometheus-pve-exporter/full-chain.pem";
+        description = ''
+          Path to a SSL certificate file for the server
+        '';
+      };
+    };
+
     collectors = {
       status = mkOption {
         type = types.bool;
         default = true;
-        description = lib.mdDoc ''
+        description = ''
           Collect Node/VM/CT status
         '';
       };
       version = mkOption {
         type = types.bool;
         default = true;
-        description = lib.mdDoc ''
+        description = ''
           Collect PVE version info
         '';
       };
       node = mkOption {
         type = types.bool;
         default = true;
-        description = lib.mdDoc ''
+        description = ''
           Collect PVE node info
         '';
       };
       cluster = mkOption {
         type = types.bool;
         default = true;
-        description = lib.mdDoc ''
+        description = ''
           Collect PVE cluster info
         '';
       };
       resources = mkOption {
         type = types.bool;
         default = true;
-        description = lib.mdDoc ''
+        description = ''
           Collect PVE resources info
         '';
       };
       config = mkOption {
         type = types.bool;
         default = true;
-        description = lib.mdDoc ''
+        description = ''
           Collect PVE onboot status
         '';
       };
@@ -102,8 +122,10 @@ in
           --${optionalString (!cfg.collectors.cluster) "no-"}collector.cluster \
           --${optionalString (!cfg.collectors.resources) "no-"}collector.resources \
           --${optionalString (!cfg.collectors.config) "no-"}collector.config \
-          %d/configFile \
-          ${toString cfg.port} ${cfg.listenAddress}
+          ${optionalString (cfg.server.keyFile != null) "--server.keyfile ${cfg.server.keyFile}"} \
+          ${optionalString (cfg.server.certFile != null) "--server.certfile ${cfg.server.certFile}"} \
+          --config.file %d/configFile \
+          --web.listen-address ${cfg.listenAddress}:${toString cfg.port}
       '';
     } // optionalAttrs (cfg.environmentFile != null) {
       EnvironmentFile = cfg.environmentFile;
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/restic.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/restic.nix
new file mode 100644
index 000000000000..5b32c93a666d
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/restic.nix
@@ -0,0 +1,131 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.restic;
+in
+{
+  port = 9753;
+  extraOpts = {
+    repository = mkOption {
+      type = types.str;
+      description = lib.mdDoc ''
+        URI pointing to the repository to monitor.
+      '';
+      example = "sftp:backup@192.168.1.100:/backups/example";
+    };
+
+    passwordFile = mkOption {
+      type = types.path;
+      description = lib.mdDoc ''
+        File containing the password to the repository.
+      '';
+      example = "/etc/nixos/restic-password";
+    };
+
+    environmentFile = mkOption {
+      type = with types; nullOr path;
+      default = null;
+      description = lib.mdDoc ''
+        File containing the credentials to access the repository, in the
+        format of an EnvironmentFile as described by systemd.exec(5)
+      '';
+    };
+
+    refreshInterval = mkOption {
+      type = types.ints.unsigned;
+      default = 60;
+      description = lib.mdDoc ''
+        Refresh interval for the metrics in seconds.
+        Computing the metrics is an expensive task, keep this value as high as possible.
+      '';
+    };
+
+    rcloneOptions = mkOption {
+      type = with types; attrsOf (oneOf [ str bool ]);
+      default = { };
+      description = lib.mdDoc ''
+        Options to pass to rclone to control its behavior.
+        See <https://rclone.org/docs/#options> for
+        available options. When specifying option names, strip the
+        leading `--`. To set a flag such as
+        `--drive-use-trash`, which does not take a value,
+        set the value to the Boolean `true`.
+      '';
+    };
+
+    rcloneConfig = mkOption {
+      type = with types; attrsOf (oneOf [ str bool ]);
+      default = { };
+      description = lib.mdDoc ''
+        Configuration for the rclone remote being used for backup.
+        See the remote's specific options under rclone's docs at
+        <https://rclone.org/docs/>. When specifying
+        option names, use the "config" name specified in the docs.
+        For example, to set `--b2-hard-delete` for a B2
+        remote, use `hard_delete = true` in the
+        attribute set.
+
+        ::: {.warning}
+        Secrets set in here will be world-readable in the Nix
+        store! Consider using the {option}`rcloneConfigFile`
+        option instead to specify secret values separately. Note that
+        options set here will override those set in the config file.
+        :::
+      '';
+    };
+
+    rcloneConfigFile = mkOption {
+      type = with types; nullOr path;
+      default = null;
+      description = lib.mdDoc ''
+        Path to the file containing rclone configuration. This file
+        must contain configuration for the remote specified in this backup
+        set and also must be readable by root.
+
+        ::: {.caution}
+        Options set in `rcloneConfig` will override those set in this
+        file.
+        :::
+      '';
+    };
+  };
+
+  serviceOpts = {
+    serviceConfig = {
+      ExecStart = ''
+        ${pkgs.prometheus-restic-exporter}/bin/restic-exporter.py \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+      EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
+    };
+    environment =
+      let
+        rcloneRemoteName = builtins.elemAt (splitString ":" cfg.repository) 1;
+        rcloneAttrToOpt = v: "RCLONE_" + toUpper (builtins.replaceStrings [ "-" ] [ "_" ] v);
+        rcloneAttrToConf = v: "RCLONE_CONFIG_" + toUpper (rcloneRemoteName + "_" + v);
+        toRcloneVal = v: if lib.isBool v then lib.boolToString v else v;
+      in
+      {
+        RESTIC_REPO_URL = cfg.repository;
+        RESTIC_REPO_PASSWORD_FILE = cfg.passwordFile;
+        LISTEN_ADDRESS = cfg.listenAddress;
+        LISTEN_PORT = toString cfg.port;
+        REFRESH_INTERVAL = toString cfg.refreshInterval;
+      }
+      // (mapAttrs'
+        (name: value:
+          nameValuePair (rcloneAttrToOpt name) (toRcloneVal value)
+        )
+        cfg.rcloneOptions)
+      // optionalAttrs (cfg.rcloneConfigFile != null) {
+        RCLONE_CONFIG = cfg.rcloneConfigFile;
+      }
+      // (mapAttrs'
+        (name: value:
+          nameValuePair (rcloneAttrToConf name) (toRcloneVal value)
+        )
+        cfg.rcloneConfig);
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix
index 840ce493ee81..452cb154bcf6 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix
@@ -3,6 +3,7 @@
 with lib;
 
 let
+  logPrefix = "services.prometheus.exporters.snmp";
   cfg = config.services.prometheus.exporters.snmp;
 
   # This ensures that we can deal with string paths, path types and
diff --git a/nixpkgs/nixos/modules/services/monitoring/riemann-dash.nix b/nixpkgs/nixos/modules/services/monitoring/riemann-dash.nix
index 1ca8af14e777..1622d7a9b920 100644
--- a/nixpkgs/nixos/modules/services/monitoring/riemann-dash.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/riemann-dash.nix
@@ -59,9 +59,10 @@ in {
       group = "riemanndash";
     };
 
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' - riemanndash riemanndash - -"
-    ];
+    systemd.tmpfiles.settings."10-riemanndash".${cfg.dataDir}.d = {
+      user = "riemanndash";
+      group = "riemanndash";
+    };
 
     systemd.services.riemann-dash = {
       wantedBy = [ "multi-user.target" ];
diff --git a/nixpkgs/nixos/modules/services/monitoring/rustdesk-server.nix b/nixpkgs/nixos/modules/services/monitoring/rustdesk-server.nix
new file mode 100644
index 000000000000..fcfd57167dd8
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/rustdesk-server.nix
@@ -0,0 +1,113 @@
+{ lib, pkgs, config, ... }:
+let
+  TCPPorts = [21115 21116 21117 21118 21119];
+  UDPPorts = [21116];
+in {
+  options.services.rustdesk-server = with lib; with types; {
+    enable = mkEnableOption "RustDesk, a remote access and remote control software, allowing maintenance of computers and other devices.";
+
+    package = mkPackageOption pkgs "rustdesk-server" {};
+
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Open the connection ports.
+        TCP (${lib.concatStringsSep ", " (map toString TCPPorts)})
+        UDP (${lib.concatStringsSep ", " (map toString UDPPorts)})
+      '';
+    };
+
+    relayIP = mkOption {
+      type = str;
+      description = ''
+        The public facing IP of the RustDesk relay.
+      '';
+    };
+
+    extraSignalArgs = mkOption {
+      type = listOf str;
+      default = [];
+      example = [ "-k" "_" ];
+      description = ''
+        A list of extra command line arguments to pass to the `hbbs` process.
+      '';
+    };
+
+    extraRelayArgs = mkOption {
+      type = listOf str;
+      default = [];
+      example = [ "-k" "_" ];
+      description = ''
+        A list of extra command line arguments to pass to the `hbbr` process.
+      '';
+    };
+  };
+
+  config = let
+    cfg = config.services.rustdesk-server;
+    serviceDefaults = {
+      enable = true;
+      requiredBy = [ "rustdesk.target" ];
+      serviceConfig = {
+        Slice = "system-rustdesk.slice";
+        User  = "rustdesk";
+        Group = "rustdesk";
+        Environment = [];
+        WorkingDirectory = "/var/lib/rustdesk";
+        StateDirectory   = "rustdesk";
+        StateDirectoryMode = "0750";
+        LockPersonality = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateMounts = true;
+        PrivateTmp = true;
+        PrivateUsers = true;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        ProtectSystem = "strict";
+        RemoveIPC = true;
+        RestrictNamespaces = true;
+        RestrictSUIDSGID = true;
+      };
+    };
+  in lib.mkIf cfg.enable {
+    users.users.rustdesk = {
+      description = "System user for RustDesk";
+      isSystemUser = true;
+      group = "rustdesk";
+    };
+    users.groups.rustdesk = {};
+
+    networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall TCPPorts;
+    networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall UDPPorts;
+
+    systemd.slices.system-rustdesk = {
+      enable = true;
+      description = "Slice designed to contain RustDesk Signal & RustDesk Relay";
+    };
+
+    systemd.targets.rustdesk = {
+      enable = true;
+      description = "Target designed to group RustDesk Signal & RustDesk Relay";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+    };
+
+    systemd.services.rustdesk-signal = lib.mkMerge [ serviceDefaults {
+      serviceConfig.ExecStart = "${cfg.package}/bin/hbbs -r ${cfg.relayIP} ${lib.escapeShellArgs cfg.extraSignalArgs}";
+    } ];
+
+    systemd.services.rustdesk-relay = lib.mkMerge [ serviceDefaults {
+      serviceConfig.ExecStart = "${cfg.package}/bin/hbbr ${lib.escapeShellArgs cfg.extraRelayArgs}";
+    } ];
+  };
+
+  meta.maintainers = with lib.maintainers; [ ppom ];
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix b/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix
index 9b1278317943..7c45247aa6d5 100644
--- a/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix
@@ -30,6 +30,7 @@ in
       description = "TeamViewer remote control daemon";
 
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" "network.target" "dbus.service" ];
       requires = [ "dbus.service" ];
       preStart = "mkdir -pv /var/lib/teamviewer /var/log/teamviewer";
diff --git a/nixpkgs/nixos/modules/services/monitoring/telegraf.nix b/nixpkgs/nixos/modules/services/monitoring/telegraf.nix
index ee28ee03adf3..3bab8aba7bd6 100644
--- a/nixpkgs/nixos/modules/services/monitoring/telegraf.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/telegraf.nix
@@ -59,6 +59,7 @@ in {
     in {
       description = "Telegraf Agent";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       path = lib.optional (config.services.telegraf.extraConfig.inputs ? procstat) pkgs.procps;
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/monitoring/watchdogd.nix b/nixpkgs/nixos/modules/services/monitoring/watchdogd.nix
new file mode 100644
index 000000000000..e8d104651c6a
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/watchdogd.nix
@@ -0,0 +1,131 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.services.watchdogd;
+
+  mkPluginOpts = plugin: defWarn: defCrit: {
+    enabled = mkEnableOption "watchdogd plugin ${plugin}";
+    interval = mkOption {
+      type = types.ints.unsigned;
+      default = 300;
+      description = ''
+        Amount of seconds between every poll.
+      '';
+    };
+    logmark = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to log current stats every poll interval.
+      '';
+    };
+    warning = mkOption {
+      type = types.numbers.nonnegative;
+      default = defWarn;
+      description = ''
+        The high watermark level. Alert sent to log.
+      '';
+    };
+    critical = mkOption {
+      type = types.numbers.nonnegative;
+      default = defCrit;
+      description = ''
+        The critical watermark level. Alert sent to log, followed by reboot or script action.
+      '';
+    };
+  };
+in {
+  options.services.watchdogd = {
+    enable = mkEnableOption "watchdogd, an advanced system & process supervisor";
+    package = mkPackageOption pkgs "watchdogd" { };
+
+    settings = mkOption {
+      type = with types; submodule {
+        freeformType = let
+          valueType = oneOf [
+            bool
+            int
+            float
+            str
+          ];
+        in attrsOf (either valueType (attrsOf valueType));
+
+        options = {
+          timeout = mkOption {
+            type = types.ints.unsigned;
+            default = 15;
+            description = ''
+              The WDT timeout before reset.
+            '';
+          };
+          interval = mkOption {
+            type = types.ints.unsigned;
+            default = 5;
+            description = ''
+              The kick interval, i.e. how often {manpage}`watchdogd(8)` should reset the WDT timer.
+            '';
+          };
+
+          safe-exit = mkOption {
+            type = types.bool;
+            default = true;
+            description = ''
+              With {var}`safeExit` enabled, the daemon will ask the driver to disable the WDT before exiting.
+              However, some WDT drivers (or hardware) may not support this.
+            '';
+          };
+
+          filenr = mkPluginOpts "filenr" 0.9 1.0;
+
+          loadavg = mkPluginOpts "loadavg" 1.0 2.0;
+
+          meminfo = mkPluginOpts "meminfo" 0.9 0.95;
+        };
+      };
+      default = { };
+      description = ''
+        Configuration to put in {file}`watchdogd.conf`.
+        See {manpage}`watchdogd.conf(5)` for more details.
+      '';
+    };
+  };
+
+  config = let
+    toConfig = attrs: concatStringsSep "\n" (mapAttrsToList toValue attrs);
+
+    toValue = name: value:
+      if isAttrs value
+        then pipe value [
+          (mapAttrsToList toValue)
+          (map (s: "  ${s}"))
+          (concatStringsSep "\n")
+          (s: "${name} {\n${s}\n}")
+        ]
+      else if isBool value
+        then "${name} = ${boolToString value}"
+      else if any (f: f value) [isString isInt isFloat]
+        then "${name} = ${toString value}"
+      else throw ''
+        Found invalid type in `services.watchdogd.settings`: '${typeOf value}'
+      '';
+
+    watchdogdConf = pkgs.writeText "watchdogd.conf" (toConfig cfg.settings);
+  in mkIf cfg.enable {
+    environment.systemPackages = [ cfg.package ];
+
+    systemd.services.watchdogd = {
+      documentation = [
+        "man:watchdogd(8)"
+        "man:watchdogd.conf(5)"
+      ];
+      wantedBy = [ "multi-user.target" ];
+      description = "Advanced system & process supervisor";
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = "${cfg.package}/bin/watchdogd -n -f ${watchdogdConf}";
+      };
+    };
+  };
+
+  meta.maintainers = with maintainers; [ vifino ];
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix b/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix
index 503e81b48a58..fea5704af6f6 100644
--- a/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix
@@ -299,10 +299,7 @@ in
         fi
       '' + optionalString (cfg.database.passwordFile != null) ''
         # create a copy of the supplied password file in a format zabbix can consume
-        touch ${passwordFile}
-        chmod 0600 ${passwordFile}
-        echo -n "DBPassword = " > ${passwordFile}
-        cat ${cfg.database.passwordFile} >> ${passwordFile}
+        install -m 0600 <(echo "DBPassword = $(cat ${cfg.database.passwordFile})") ${passwordFile}
       '';
 
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/monitoring/zabbix-server.nix b/nixpkgs/nixos/modules/services/monitoring/zabbix-server.nix
index 0607188d2131..f2fb5fbe7ac6 100644
--- a/nixpkgs/nixos/modules/services/monitoring/zabbix-server.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/zabbix-server.nix
@@ -292,10 +292,7 @@ in
         fi
       '' + optionalString (cfg.database.passwordFile != null) ''
         # create a copy of the supplied password file in a format zabbix can consume
-        touch ${passwordFile}
-        chmod 0600 ${passwordFile}
-        echo -n "DBPassword = " > ${passwordFile}
-        cat ${cfg.database.passwordFile} >> ${passwordFile}
+        install -m 0600 <(echo "DBPassword = $(cat ${cfg.database.passwordFile})") ${passwordFile}
       '';
 
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/cachefilesd.nix b/nixpkgs/nixos/modules/services/network-filesystems/cachefilesd.nix
index da5a79a062c7..3fb6a19c6fa3 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/cachefilesd.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/cachefilesd.nix
@@ -56,8 +56,10 @@ in
       };
     };
 
-    systemd.tmpfiles.rules = [
-      "d ${cfg.cacheDir} 0700 root root - -"
-    ];
+    systemd.tmpfiles.settings."10-cachefilesd".${cfg.cacheDir}.d = {
+      user = "root";
+      group = "root";
+      mode = "0700";
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix b/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix
index 222905223b59..df9a2f802bb9 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix
@@ -398,12 +398,18 @@ in
       in
         mkMerge targets;
 
-    systemd.tmpfiles.rules = [
-      "d /etc/ceph - ceph ceph - -"
-      "d /run/ceph 0770 ceph ceph -"
-      "d /var/lib/ceph - ceph ceph - -"]
-    ++ optionals cfg.mgr.enable [ "d /var/lib/ceph/mgr - ceph ceph - -"]
-    ++ optionals cfg.mon.enable [ "d /var/lib/ceph/mon - ceph ceph - -"]
-    ++ optionals cfg.osd.enable [ "d /var/lib/ceph/osd - ceph ceph - -"];
+    systemd.tmpfiles.settings."10-ceph" = let
+      defaultConfig = {
+        user = "ceph";
+        group = "ceph";
+      };
+    in {
+      "/etc/ceph".d = defaultConfig;
+      "/run/ceph".d = defaultConfig // { mode = "0770"; };
+      "/var/lib/ceph".d = defaultConfig;
+      "/var/lib/ceph/mgr".d = mkIf (cfg.mgr.enable) defaultConfig;
+      "/var/lib/ceph/mon".d = mkIf (cfg.mon.enable) defaultConfig;
+      "/var/lib/ceph/osd".d = mkIf (cfg.osd.enable) defaultConfig;
+    };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/kbfs.nix b/nixpkgs/nixos/modules/services/network-filesystems/kbfs.nix
index 33ff283d5e81..578675e75dc3 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/kbfs.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/kbfs.nix
@@ -92,7 +92,12 @@ in {
     (mkIf cfg.enableRedirector {
       security.wrappers."keybase-redirector".source = "${pkgs.kbfs}/bin/redirector";
 
-      systemd.tmpfiles.rules = [ "d /keybase 0755 root root 0" ];
+      systemd.tmpfiles.settings."10-kbfs"."/keybase".d = {
+        user = "root";
+        group = "root";
+        mode = "0755";
+        age = "0";
+      };
 
       # Upstream: https://github.com/keybase/client/blob/master/packaging/linux/systemd/keybase-redirector.service
       systemd.user.services.keybase-redirector = {
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/kubo.nix b/nixpkgs/nixos/modules/services/network-filesystems/kubo.nix
index 10162c1633e7..9a05a28550d3 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/kubo.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/kubo.nix
@@ -312,12 +312,13 @@ in
       ipfs.gid = config.ids.gids.ipfs;
     };
 
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' - ${cfg.user} ${cfg.group} - -"
-    ] ++ optionals cfg.autoMount [
-      "d '${cfg.settings.Mounts.IPFS}' - ${cfg.user} ${cfg.group} - -"
-      "d '${cfg.settings.Mounts.IPNS}' - ${cfg.user} ${cfg.group} - -"
-    ];
+    systemd.tmpfiles.settings."10-kubo" = let
+      defaultConfig = { inherit (cfg) user group; };
+    in {
+      ${cfg.dataDir}.d = defaultConfig;
+      ${cfg.settings.Mounts.IPFS}.d = mkIf (cfg.autoMount) defaultConfig;
+      ${cfg.settings.Mounts.IPNS}.d = mkIf (cfg.autoMount) defaultConfig;
+    };
 
     # The hardened systemd unit breaks the fuse-mount function according to documentation in the unit file itself
     systemd.packages = if cfg.autoMount
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix b/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix
index bb0fee087e62..02c3482ec657 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix
@@ -215,6 +215,7 @@ in
     systemd.services.afsd = {
       description = "AFS client";
       wantedBy = [ "multi-user.target" ];
+      wants = lib.optional (!cfg.startDisconnected) "network-online.target";
       after = singleton (if cfg.startDisconnected then  "network.target" else "network-online.target");
       serviceConfig = { RemainAfterExit = true; };
       restartIfChanged = false;
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/samba.nix b/nixpkgs/nixos/modules/services/network-filesystems/samba.nix
index 5d02eac8e9f1..ef368ddbeefd 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/samba.nix
@@ -154,7 +154,7 @@ in
       };
 
       securityType = mkOption {
-        type = types.str;
+        type = types.enum [ "auto" "user" "domain" "ads" ];
         default = "user";
         description = lib.mdDoc "Samba security type";
       };
diff --git a/nixpkgs/nixos/modules/services/networking/aria2.nix b/nixpkgs/nixos/modules/services/networking/aria2.nix
index e848869cc0ac..1fb55b836798 100644
--- a/nixpkgs/nixos/modules/services/networking/aria2.nix
+++ b/nixpkgs/nixos/modules/services/networking/aria2.nix
@@ -18,11 +18,14 @@ let
     dir=${cfg.downloadDir}
     listen-port=${concatStringsSep "," (rangesToStringList cfg.listenPortRange)}
     rpc-listen-port=${toString cfg.rpcListenPort}
-    rpc-secret=${cfg.rpcSecret}
   '';
 
 in
 {
+  imports = [
+    (mkRemovedOptionModule [ "services" "aria2" "rpcSecret" ] "Use services.aria2.rpcSecretFile instead")
+  ];
+
   options = {
     services.aria2 = {
       enable = mkOption {
@@ -65,11 +68,11 @@ in
         default = 6800;
         description = lib.mdDoc "Specify a port number for JSON-RPC/XML-RPC server to listen to. Possible Values: 1024-65535";
       };
-      rpcSecret = mkOption {
-        type = types.str;
-        default = "aria2rpc";
+      rpcSecretFile = mkOption {
+        type = types.path;
+        example = "/run/secrets/aria2-rpc-token.txt";
         description = lib.mdDoc ''
-          Set RPC secret authorization token.
+          A file containing the RPC secret authorization token.
           Read https://aria2.github.io/manual/en/html/aria2c.html#rpc-auth to know how this option value is used.
         '';
       };
@@ -117,6 +120,7 @@ in
           touch "${sessionFile}"
         fi
         cp -f "${settingsFile}" "${settingsDir}/aria2.conf"
+        echo "rpc-secret=$(cat "$CREDENTIALS_DIRECTORY/rpcSecretFile")" >> "${settingsDir}/aria2.conf"
       '';
 
       serviceConfig = {
@@ -125,6 +129,7 @@ in
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         User = "aria2";
         Group = "aria2";
+        LoadCredential="rpcSecretFile:${cfg.rpcSecretFile}";
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/networking/bird.nix b/nixpkgs/nixos/modules/services/networking/bird.nix
index 9deeb7694d2a..e25f5c7b0379 100644
--- a/nixpkgs/nixos/modules/services/networking/bird.nix
+++ b/nixpkgs/nixos/modules/services/networking/bird.nix
@@ -18,6 +18,13 @@ in
           <http://bird.network.cz/>
         '';
       };
+      autoReload = mkOption {
+        type = types.bool;
+        default = true;
+        description = lib.mdDoc ''
+          Whether bird2 should be automatically reloaded when the configuration changes.
+        '';
+      };
       checkConfig = mkOption {
         type = types.bool;
         default = true;
@@ -68,7 +75,7 @@ in
     systemd.services.bird2 = {
       description = "BIRD Internet Routing Daemon";
       wantedBy = [ "multi-user.target" ];
-      reloadTriggers = [ config.environment.etc."bird/bird2.conf".source ];
+      reloadTriggers = lib.optional cfg.autoReload config.environment.etc."bird/bird2.conf".source;
       serviceConfig = {
         Type = "forking";
         Restart = "on-failure";
diff --git a/nixpkgs/nixos/modules/services/networking/bitcoind.nix b/nixpkgs/nixos/modules/services/networking/bitcoind.nix
index 4512e666ba5b..59722e31c62a 100644
--- a/nixpkgs/nixos/modules/services/networking/bitcoind.nix
+++ b/nixpkgs/nixos/modules/services/networking/bitcoind.nix
@@ -198,6 +198,7 @@ in
         '';
       in {
         description = "Bitcoin daemon";
+        wants = [ "network-online.target" ];
         after = [ "network-online.target" ];
         wantedBy = [ "multi-user.target" ];
         serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/networking/charybdis.nix b/nixpkgs/nixos/modules/services/networking/charybdis.nix
index 168da243dba1..6eacdde7bb93 100644
--- a/nixpkgs/nixos/modules/services/networking/charybdis.nix
+++ b/nixpkgs/nixos/modules/services/networking/charybdis.nix
@@ -81,9 +81,9 @@ in
         gid = config.ids.gids.ircd;
       };
 
-      systemd.tmpfiles.rules = [
-        "d ${cfg.statedir} - ${cfg.user} ${cfg.group} - -"
-      ];
+      systemd.tmpfiles.settings."10-charybdis".${cfg.statedir}.d = {
+        inherit (cfg) user group;
+      };
 
       environment.etc."charybdis/ircd.conf".source = configFile;
 
diff --git a/nixpkgs/nixos/modules/services/networking/cloudflared.nix b/nixpkgs/nixos/modules/services/networking/cloudflared.nix
index 80c60fdb8013..b9556bfa60d0 100644
--- a/nixpkgs/nixos/modules/services/networking/cloudflared.nix
+++ b/nixpkgs/nixos/modules/services/networking/cloudflared.nix
@@ -276,9 +276,11 @@ in
             ingressesSet = filterIngressSet tunnel.ingress;
             ingressesStr = filterIngressStr tunnel.ingress;
 
-            fullConfig = {
+            fullConfig = filterConfig {
               tunnel = name;
               "credentials-file" = tunnel.credentialsFile;
+              warp-routing = filterConfig tunnel.warp-routing;
+              originRequest = filterConfig tunnel.originRequest;
               ingress =
                 (map
                   (key: {
@@ -294,6 +296,7 @@ in
                   (attrNames ingressesStr))
                 ++ [{ service = tunnel.default; }];
             };
+
             mkConfigFile = pkgs.writeText "cloudflared.yml" (builtins.toJSON fullConfig);
           in
           nameValuePair "cloudflared-tunnel-${name}" ({
@@ -322,5 +325,5 @@ in
     };
   };
 
-  meta.maintainers = with maintainers; [ bbigras ];
+  meta.maintainers = with maintainers; [ bbigras anpin ];
 }
diff --git a/nixpkgs/nixos/modules/services/networking/dante.nix b/nixpkgs/nixos/modules/services/networking/dante.nix
index 605f2d74f827..f0d1d6305c54 100644
--- a/nixpkgs/nixos/modules/services/networking/dante.nix
+++ b/nixpkgs/nixos/modules/services/networking/dante.nix
@@ -47,6 +47,7 @@ in
 
     systemd.services.dante = {
       description   = "Dante SOCKS v4 and v5 compatible proxy server";
+      wants         = [ "network-online.target" ];
       after         = [ "network-online.target" ];
       wantedBy      = [ "multi-user.target" ];
 
diff --git a/nixpkgs/nixos/modules/services/networking/dhcpcd.nix b/nixpkgs/nixos/modules/services/networking/dhcpcd.nix
index 2b59352ac616..266a7ea1435e 100644
--- a/nixpkgs/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixpkgs/nixos/modules/services/networking/dhcpcd.nix
@@ -219,6 +219,8 @@ in
       '';
     } ];
 
+    environment.etc."dhcpcd.conf".source = dhcpcdConf;
+
     systemd.services.dhcpcd = let
       cfgN = config.networking;
       hasDefaultGatewaySet = (cfgN.defaultGateway != null && cfgN.defaultGateway.address != "")
diff --git a/nixpkgs/nixos/modules/services/networking/dnsdist.nix b/nixpkgs/nixos/modules/services/networking/dnsdist.nix
index 483300111df9..792185c9fbea 100644
--- a/nixpkgs/nixos/modules/services/networking/dnsdist.nix
+++ b/nixpkgs/nixos/modules/services/networking/dnsdist.nix
@@ -4,10 +4,79 @@ with lib;
 
 let
   cfg = config.services.dnsdist;
+
+  toLua = lib.generators.toLua {};
+
+  mkBind = cfg: toLua "${cfg.listenAddress}:${toString cfg.listenPort}";
+
   configFile = pkgs.writeText "dnsdist.conf" ''
-    setLocal('${cfg.listenAddress}:${toString cfg.listenPort}')
+    setLocal(${mkBind cfg})
+    ${lib.optionalString cfg.dnscrypt.enable dnscryptSetup}
     ${cfg.extraConfig}
   '';
+
+  dnscryptSetup = ''
+    last_rotation = 0
+    cert_serial = 0
+    provider_key = ${toLua cfg.dnscrypt.providerKey}
+    cert_lifetime = ${toLua cfg.dnscrypt.certLifetime} * 60
+
+    function file_exists(name)
+       local f = io.open(name, "r")
+       return f ~= nil and io.close(f)
+    end
+
+    function dnscrypt_setup()
+      -- generate provider keys on first run
+      if provider_key == nil then
+        provider_key = "/var/lib/dnsdist/private.key"
+        if not file_exists(provider_key) then
+          generateDNSCryptProviderKeys("/var/lib/dnsdist/public.key",
+                                       "/var/lib/dnsdist/private.key")
+          print("DNSCrypt: generated provider keypair")
+        end
+      end
+
+      -- generate resolver certificate
+      local now = os.time()
+      generateDNSCryptCertificate(
+        provider_key, "/run/dnsdist/resolver.cert", "/run/dnsdist/resolver.key",
+        cert_serial, now - 60, now + cert_lifetime)
+      addDNSCryptBind(
+        ${mkBind cfg.dnscrypt}, ${toLua cfg.dnscrypt.providerName},
+        "/run/dnsdist/resolver.cert", "/run/dnsdist/resolver.key")
+    end
+
+    function maintenance()
+      -- certificate rotation
+      local now = os.time()
+      local dnscrypt = getDNSCryptBind(0)
+
+      if ((now - last_rotation) > 0.9 * cert_lifetime) then
+        -- generate and start using a new certificate
+        dnscrypt:generateAndLoadInMemoryCertificate(
+          provider_key, cert_serial + 1,
+          now - 60, now + cert_lifetime)
+
+        -- stop advertising the last certificate
+        dnscrypt:markInactive(cert_serial)
+
+        -- remove the second to last certificate
+        if (cert_serial > 1)  then
+          dnscrypt:removeInactiveCertificate(cert_serial - 1)
+        end
+
+        print("DNSCrypt: rotated certificate")
+
+        -- increment serial number
+        cert_serial = cert_serial + 1
+        last_rotation = now
+      end
+    end
+
+    dnscrypt_setup()
+  '';
+
 in {
   options = {
     services.dnsdist = {
@@ -15,15 +84,69 @@ in {
 
       listenAddress = mkOption {
         type = types.str;
-        description = lib.mdDoc "Listen IP Address";
+        description = lib.mdDoc "Listen IP address";
         default = "0.0.0.0";
       };
       listenPort = mkOption {
-        type = types.int;
+        type = types.port;
         description = lib.mdDoc "Listen port";
         default = 53;
       };
 
+      dnscrypt = {
+        enable = mkEnableOption (lib.mdDoc "a DNSCrypt endpoint to dnsdist");
+
+        listenAddress = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Listen IP address of the endpoint";
+          default = "0.0.0.0";
+        };
+
+        listenPort = mkOption {
+          type = types.port;
+          description = lib.mdDoc "Listen port of the endpoint";
+          default = 443;
+        };
+
+        providerName = mkOption {
+          type = types.str;
+          default = "2.dnscrypt-cert.${config.networking.hostName}";
+          defaultText = literalExpression "2.dnscrypt-cert.\${config.networking.hostName}";
+          example = "2.dnscrypt-cert.myresolver";
+          description = lib.mdDoc ''
+            The name that will be given to this DNSCrypt resolver.
+
+            ::: {.note}
+            The provider name must start with `2.dnscrypt-cert.`.
+            :::
+          '';
+        };
+
+        providerKey = mkOption {
+          type = types.nullOr types.path;
+          default = null;
+          description = lib.mdDoc ''
+            The filepath to the provider secret key.
+            If not given a new provider key pair will be generated in
+            /var/lib/dnsdist on the first run.
+
+            ::: {.note}
+            The file must be readable by the dnsdist user/group.
+            :::
+          '';
+        };
+
+        certLifetime = mkOption {
+          type = types.ints.positive;
+          default = 15;
+          description = lib.mdDoc ''
+            The lifetime (in minutes) of the resolver certificate.
+            This will be automatically rotated before expiration.
+          '';
+        };
+
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         default = "";
@@ -35,6 +158,14 @@ in {
   };
 
   config = mkIf cfg.enable {
+    users.users.dnsdist = {
+      description = "dnsdist daemons user";
+      isSystemUser = true;
+      group = "dnsdist";
+    };
+
+    users.groups.dnsdist = {};
+
     systemd.packages = [ pkgs.dnsdist ];
 
     systemd.services.dnsdist = {
@@ -42,8 +173,10 @@ in {
 
       startLimitIntervalSec = 0;
       serviceConfig = {
-        DynamicUser = true;
-
+        User = "dnsdist";
+        Group = "dnsdist";
+        RuntimeDirectory = "dnsdist";
+        StateDirectory = "dnsdist";
         # 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/ergo.nix b/nixpkgs/nixos/modules/services/networking/ergo.nix
index 033d4d9caf8a..1bee0f43f988 100644
--- a/nixpkgs/nixos/modules/services/networking/ergo.nix
+++ b/nixpkgs/nixos/modules/services/networking/ergo.nix
@@ -114,6 +114,7 @@ in {
     systemd.services.ergo = {
       description = "ergo server";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       serviceConfig = {
         User = cfg.user;
diff --git a/nixpkgs/nixos/modules/services/networking/expressvpn.nix b/nixpkgs/nixos/modules/services/networking/expressvpn.nix
index 30de6987d31f..05c24d8bccff 100644
--- a/nixpkgs/nixos/modules/services/networking/expressvpn.nix
+++ b/nixpkgs/nixos/modules/services/networking/expressvpn.nix
@@ -21,6 +21,7 @@ with lib;
         RestartSec = 5;
       };
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network.target" "network-online.target" ];
     };
   };
diff --git a/nixpkgs/nixos/modules/services/networking/headscale.nix b/nixpkgs/nixos/modules/services/networking/headscale.nix
index 4224a0578cc3..0159da37de87 100644
--- a/nixpkgs/nixos/modules/services/networking/headscale.nix
+++ b/nixpkgs/nixos/modules/services/networking/headscale.nix
@@ -444,10 +444,14 @@ in {
       tls_letsencrypt_cache_dir = "${dataDir}/.cache";
     };
 
-    # Setup the headscale configuration in a known path in /etc to
-    # allow both the Server and the Client use it to find the socket
-    # for communication.
-    environment.etc."headscale/config.yaml".source = configFile;
+    environment = {
+      # Setup the headscale configuration in a known path in /etc to
+      # allow both the Server and the Client use it to find the socket
+      # for communication.
+      etc."headscale/config.yaml".source = configFile;
+
+      systemPackages = [ cfg.package ];
+    };
 
     users.groups.headscale = mkIf (cfg.group == "headscale") {};
 
@@ -460,6 +464,7 @@ in {
 
     systemd.services.headscale = {
       description = "headscale coordination server for Tailscale";
+      wants = [ "network-online.target" ];
       after = ["network-online.target"];
       wantedBy = ["multi-user.target"];
       restartTriggers = [configFile];
diff --git a/nixpkgs/nixos/modules/services/networking/hostapd.nix b/nixpkgs/nixos/modules/services/networking/hostapd.nix
index 5bd8e1d4d7a0..00482e59acf3 100644
--- a/nixpkgs/nixos/modules/services/networking/hostapd.nix
+++ b/nixpkgs/nixos/modules/services/networking/hostapd.nix
@@ -1197,8 +1197,6 @@ in {
 
     environment.systemPackages = [cfg.package];
 
-    services.udev.packages = with pkgs; [crda];
-
     systemd.services.hostapd = {
       description = "IEEE 802.11 Host Access-Point Daemon";
 
diff --git a/nixpkgs/nixos/modules/services/networking/ircd-hybrid/default.nix b/nixpkgs/nixos/modules/services/networking/ircd-hybrid/default.nix
index 554b0f7bb8b4..64a34cc52d25 100644
--- a/nixpkgs/nixos/modules/services/networking/ircd-hybrid/default.nix
+++ b/nixpkgs/nixos/modules/services/networking/ircd-hybrid/default.nix
@@ -125,7 +125,8 @@ in
 
     systemd.services.ircd-hybrid = {
       description = "IRCD Hybrid server";
-      after = [ "started networking" ];
+      wants = [ "network-online.target" ];
+      after = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
       script = "${ircdService}/bin/control start";
     };
diff --git a/nixpkgs/nixos/modules/services/networking/ivpn.nix b/nixpkgs/nixos/modules/services/networking/ivpn.nix
index 6df630c1f194..6c9ae599e670 100644
--- a/nixpkgs/nixos/modules/services/networking/ivpn.nix
+++ b/nixpkgs/nixos/modules/services/networking/ivpn.nix
@@ -27,7 +27,7 @@ with lib;
     systemd.services.ivpn-service = {
       description = "iVPN daemon";
       wantedBy = [ "multi-user.target" ];
-      wants = [ "network.target" ];
+      wants = [ "network.target" "network-online.target" ];
       after = [
         "network-online.target"
         "NetworkManager.service"
diff --git a/nixpkgs/nixos/modules/services/networking/jibri/default.nix b/nixpkgs/nixos/modules/services/networking/jibri/default.nix
index a931831fc281..dfba38896a91 100644
--- a/nixpkgs/nixos/modules/services/networking/jibri/default.nix
+++ b/nixpkgs/nixos/modules/services/networking/jibri/default.nix
@@ -5,12 +5,7 @@ with lib;
 let
   cfg = config.services.jibri;
 
-  # Copied from the jitsi-videobridge.nix file.
-  toHOCON = x:
-    if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
-    else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
-    else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
-    else builtins.toJSON x;
+  format = pkgs.formats.hocon { };
 
   # We're passing passwords in environment variables that have names generated
   # from an attribute name, which may not be a valid bash identifier.
@@ -38,13 +33,13 @@ let
         control-login = {
           domain = env.control.login.domain;
           username = env.control.login.username;
-          password.__hocon_envvar = toVarName "${name}_control";
+          password = format.lib.mkSubstitution (toVarName "${name}_control");
         };
 
         call-login = {
           domain = env.call.login.domain;
           username = env.call.login.username;
-          password.__hocon_envvar = toVarName "${name}_call";
+          password = format.lib.mkSubstitution (toVarName "${name}_call");
         };
 
         strip-from-room-domain = env.stripFromRoomDomain;
@@ -85,13 +80,13 @@ let
   };
   # Allow overriding leaves of the default config despite types.attrs not doing any merging.
   jibriConfig = recursiveUpdate defaultJibriConfig cfg.config;
-  configFile = pkgs.writeText "jibri.conf" (toHOCON { jibri = jibriConfig; });
+  configFile = format.generate "jibri.conf" { jibri = jibriConfig; };
 in
 {
   options.services.jibri = with types; {
     enable = mkEnableOption (lib.mdDoc "Jitsi BRoadcasting Infrastructure. Currently Jibri must be run on a host that is also running {option}`services.jitsi-meet.enable`, so for most use cases it will be simpler to run {option}`services.jitsi-meet.jibri.enable`");
     config = mkOption {
-      type = attrs;
+      type = format.type;
       default = { };
       description = lib.mdDoc ''
         Jibri configuration.
@@ -395,11 +390,11 @@ in
       };
     };
 
-    systemd.tmpfiles.rules = [
-      "d /var/log/jitsi/jibri 755 jibri jibri"
-    ];
-
-
+    systemd.tmpfiles.settings."10-jibri"."/var/log/jitsi/jibri".d = {
+      user = "jibri";
+      group = "jibri";
+      mode = "755";
+    };
 
     # Configure Chromium to not show the "Chrome is being controlled by automatic test software" message.
     environment.etc."chromium/policies/managed/managed_policies.json".text = builtins.toJSON { CommandLineFlagSecurityWarningsEnabled = false; };
diff --git a/nixpkgs/nixos/modules/services/networking/jicofo.nix b/nixpkgs/nixos/modules/services/networking/jicofo.nix
index 0886bbe004c4..380344c8eaa1 100644
--- a/nixpkgs/nixos/modules/services/networking/jicofo.nix
+++ b/nixpkgs/nixos/modules/services/networking/jicofo.nix
@@ -5,14 +5,9 @@ with lib;
 let
   cfg = config.services.jicofo;
 
-  # HOCON is a JSON superset that some jitsi-meet components use for configuration
-  toHOCON = x: if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
-    else if isAttrs x && x ? __hocon_unquoted_string then x.__hocon_unquoted_string
-    else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
-    else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
-    else builtins.toJSON x;
-
-  configFile = pkgs.writeText "jicofo.conf" (toHOCON cfg.config);
+  format = pkgs.formats.hocon { };
+
+  configFile = format.generate "jicofo.conf" cfg.config;
 in
 {
   options.services.jicofo = with types; {
@@ -77,7 +72,7 @@ in
     };
 
     config = mkOption {
-      type = (pkgs.formats.json {}).type;
+      type = format.type;
       default = { };
       example = literalExpression ''
         {
@@ -99,7 +94,7 @@ in
             hostname = cfg.xmppHost;
             username = cfg.userName;
             domain = cfg.userDomain;
-            password = { __hocon_envvar = "JICOFO_AUTH_PASS"; };
+            password = format.lib.mkSubstitution "JICOFO_AUTH_PASS";
             xmpp-domain = if cfg.xmppDomain == null then cfg.xmppHost else cfg.xmppDomain;
           };
           service = client;
diff --git a/nixpkgs/nixos/modules/services/networking/jitsi-videobridge.nix b/nixpkgs/nixos/modules/services/networking/jitsi-videobridge.nix
index 37b0b1e5bf50..00ea5b9da546 100644
--- a/nixpkgs/nixos/modules/services/networking/jitsi-videobridge.nix
+++ b/nixpkgs/nixos/modules/services/networking/jitsi-videobridge.nix
@@ -6,16 +6,7 @@ let
   cfg = config.services.jitsi-videobridge;
   attrsToArgs = a: concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") a);
 
-  # HOCON is a JSON superset that videobridge2 uses for configuration.
-  # It can substitute environment variables which we use for passwords here.
-  # https://github.com/lightbend/config/blob/master/README.md
-  #
-  # Substitution for environment variable FOO is represented as attribute set
-  # { __hocon_envvar = "FOO"; }
-  toHOCON = x: if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
-    else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
-    else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
-    else builtins.toJSON x;
+  format = pkgs.formats.hocon { };
 
   # We're passing passwords in environment variables that have names generated
   # from an attribute name, which may not be a valid bash identifier.
@@ -38,7 +29,7 @@ let
         hostname = xmppConfig.hostName;
         domain = xmppConfig.domain;
         username = xmppConfig.userName;
-        password = { __hocon_envvar = toVarName name; };
+        password = format.lib.mkSubstitution (toVarName name);
         muc_jids = xmppConfig.mucJids;
         muc_nickname = xmppConfig.mucNickname;
         disable_certificate_verification = xmppConfig.disableCertificateVerification;
@@ -221,7 +212,7 @@ in
         "-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
         "-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "videobridge";
         "-Djava.util.logging.config.file" = "/etc/jitsi/videobridge/logging.properties";
-        "-Dconfig.file" = pkgs.writeText "jvb.conf" (toHOCON jvbConfig);
+        "-Dconfig.file" = format.generate "jvb.conf" jvbConfig;
         # Mitigate CVE-2021-44228
         "-Dlog4j2.formatMsgNoLookups" = true;
       } // (mapAttrs' (k: v: nameValuePair "-D${k}" v) cfg.extraProperties);
diff --git a/nixpkgs/nixos/modules/services/networking/kea.nix b/nixpkgs/nixos/modules/services/networking/kea.nix
index 5ca705976c41..656ddd41fd12 100644
--- a/nixpkgs/nixos/modules/services/networking/kea.nix
+++ b/nixpkgs/nixos/modules/services/networking/kea.nix
@@ -325,6 +325,9 @@ in
         "network-online.target"
         "time-sync.target"
       ];
+      wants = [
+        "network-online.target"
+      ];
       wantedBy = [
         "multi-user.target"
       ];
@@ -372,6 +375,9 @@ in
         "network-online.target"
         "time-sync.target"
       ];
+      wants = [
+        "network-online.target"
+      ];
       wantedBy = [
         "multi-user.target"
       ];
@@ -413,6 +419,7 @@ in
         "https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html"
       ];
 
+      wants = [ "network-online.target" ];
       after = [
         "network-online.target"
         "time-sync.target"
diff --git a/nixpkgs/nixos/modules/services/networking/keepalived/default.nix b/nixpkgs/nixos/modules/services/networking/keepalived/default.nix
index 429a47c3962c..599dfd52e271 100644
--- a/nixpkgs/nixos/modules/services/networking/keepalived/default.nix
+++ b/nixpkgs/nixos/modules/services/networking/keepalived/default.nix
@@ -59,9 +59,11 @@ let
         ${optionalString i.vmacXmitBase "vmac_xmit_base"}
 
         ${optionalString (i.unicastSrcIp != null) "unicast_src_ip ${i.unicastSrcIp}"}
-        unicast_peer {
-          ${concatStringsSep "\n" i.unicastPeers}
-        }
+        ${optionalString (builtins.length i.unicastPeers > 0) ''
+          unicast_peer {
+            ${concatStringsSep "\n" i.unicastPeers}
+          }
+        ''}
 
         virtual_ipaddress {
           ${concatMapStringsSep "\n" virtualIpLine i.virtualIps}
@@ -138,6 +140,7 @@ let
 
 in
 {
+  meta.maintainers = [ lib.maintainers.raitobezarius ];
 
   options = {
     services.keepalived = {
diff --git a/nixpkgs/nixos/modules/services/networking/knot.nix b/nixpkgs/nixos/modules/services/networking/knot.nix
index d4bd81629c97..94c32586736a 100644
--- a/nixpkgs/nixos/modules/services/networking/knot.nix
+++ b/nixpkgs/nixos/modules/services/networking/knot.nix
@@ -44,6 +44,7 @@ let
         ++ [ (sec_list_fa "id" nix_def "template") ]
         ++ [ (sec_list_fa "domain" nix_def "zone") ]
         ++ [ (sec_plain nix_def "include") ]
+        ++ [ (sec_plain nix_def "clear") ]
       );
 
     # A plain section contains directly attributes (we don't really check that ATM).
diff --git a/nixpkgs/nixos/modules/services/networking/kresd.nix b/nixpkgs/nixos/modules/services/networking/kresd.nix
index 0c7363e564dc..307414abf170 100644
--- a/nixpkgs/nixos/modules/services/networking/kresd.nix
+++ b/nixpkgs/nixos/modules/services/networking/kresd.nix
@@ -11,7 +11,7 @@ let
   mkListen = kind: addr: let
     al_v4 = builtins.match "([0-9.]+):([0-9]+)($)" addr;
     al_v6 = builtins.match "\\[(.+)]:([0-9]+)(%.*|$)" addr;
-    al_portOnly = builtins.match "([0-9]+)" addr;
+    al_portOnly = builtins.match "(^)([0-9]+)" addr;
     al = findFirst (a: a != null)
       (throw "services.kresd.*: incorrect address specification '${addr}'")
       [ al_v4 al_v6 al_portOnly ];
diff --git a/nixpkgs/nixos/modules/services/networking/mosquitto.nix b/nixpkgs/nixos/modules/services/networking/mosquitto.nix
index f2b158b98942..ad9eefb42252 100644
--- a/nixpkgs/nixos/modules/services/networking/mosquitto.nix
+++ b/nixpkgs/nixos/modules/services/networking/mosquitto.nix
@@ -596,6 +596,7 @@ in
     systemd.services.mosquitto = {
       description = "Mosquitto MQTT Broker Daemon";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       serviceConfig = {
         Type = "notify";
diff --git a/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix b/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix
index 446c71f40764..5da4ca1d1d80 100644
--- a/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix
+++ b/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix
@@ -53,7 +53,7 @@ with lib;
     systemd.services.mullvad-daemon = {
       description = "Mullvad VPN daemon";
       wantedBy = [ "multi-user.target" ];
-      wants = [ "network.target" ];
+      wants = [ "network.target" "network-online.target" ];
       after = [
         "network-online.target"
         "NetworkManager.service"
diff --git a/nixpkgs/nixos/modules/services/networking/murmur.nix b/nixpkgs/nixos/modules/services/networking/murmur.nix
index 0cd80e134ace..5805f332a66f 100644
--- a/nixpkgs/nixos/modules/services/networking/murmur.nix
+++ b/nixpkgs/nixos/modules/services/networking/murmur.nix
@@ -326,6 +326,29 @@ in
         RuntimeDirectoryMode = "0700";
         User = "murmur";
         Group = "murmur";
+
+        # service hardening
+        AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+        CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateTmp = true;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectSystem = "full";
+        RestrictAddressFamilies = "~AF_PACKET AF_NETLINK";
+        RestrictNamespaces = true;
+        RestrictSUIDSGID = true;
+        RestrictRealtime = true;
+        SystemCallArchitectures = "native";
+        SystemCallFilter = "@system-service";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/networking/nbd.nix b/nixpkgs/nixos/modules/services/networking/nbd.nix
index 454380aa3154..b4bf7ede8463 100644
--- a/nixpkgs/nixos/modules/services/networking/nbd.nix
+++ b/nixpkgs/nixos/modules/services/networking/nbd.nix
@@ -117,6 +117,7 @@ in
     boot.kernelModules = [ "nbd" ];
 
     systemd.services.nbd-server = {
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       before = [ "multi-user.target" ];
       wantedBy = [ "multi-user.target" ];
diff --git a/nixpkgs/nixos/modules/services/networking/netbird.md b/nixpkgs/nixos/modules/services/networking/netbird.md
new file mode 100644
index 000000000000..a326207becc8
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/netbird.md
@@ -0,0 +1,56 @@
+# Netbird {#module-services-netbird}
+
+## Quickstart {#module-services-netbird-quickstart}
+
+The absolute minimal configuration for the netbird daemon looks like this:
+
+```nix
+services.netbird.enable = true;
+```
+
+This will set up a netbird service listening on the port `51820` associated to the
+`wt0` interface.
+
+It is strictly equivalent to setting:
+
+```nix
+services.netbird.tunnels.wt0.stateDir = "netbird";
+```
+
+The `enable` option is mainly kept for backward compatibility, as defining netbird
+tunnels through the `tunnels` option is more expressive.
+
+## Multiple connections setup {#module-services-netbird-multiple-connections}
+
+Using the `services.netbird.tunnels` option, it is also possible to define more than
+one netbird service running at the same time.
+
+The following configuration will start a netbird daemon using the interface `wt1` and
+the port 51830. Its configuration file will then be located at `/var/lib/netbird-wt1/config.json`.
+
+```nix
+services.netbird.tunnels = {
+  wt1 = {
+    port = 51830;
+  };
+};
+```
+
+To interact with it, you will need to specify the correct daemon address:
+
+```bash
+netbird --daemon-addr unix:///var/run/netbird-wt1/sock ...
+```
+
+The address will by default be `unix:///var/run/netbird-<name>`.
+
+It is also possible to overwrite default options passed to the service, for
+example:
+
+```nix
+services.netbird.tunnels.wt1.environment = {
+  NB_DAEMON_ADDR = "unix:///var/run/toto.sock"
+};
+```
+
+This will set the socket to interact with the netbird service to `/var/run/toto.sock`.
diff --git a/nixpkgs/nixos/modules/services/networking/netbird.nix b/nixpkgs/nixos/modules/services/networking/netbird.nix
index 4b0bd63e9dbc..6a1511d4d084 100644
--- a/nixpkgs/nixos/modules/services/networking/netbird.nix
+++ b/nixpkgs/nixos/modules/services/networking/netbird.nix
@@ -1,60 +1,171 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
 
 let
-  cfg = config.services.netbird;
+  inherit (lib)
+    attrNames
+    getExe
+    literalExpression
+    maintainers
+    mapAttrs'
+    mkDefault
+    mkEnableOption
+    mkIf
+    mkMerge
+    mkOption
+    mkPackageOption
+    nameValuePair
+    optional
+    versionOlder
+    ;
+
+  inherit (lib.types)
+    attrsOf
+    port
+    str
+    submodule
+    ;
+
   kernel = config.boot.kernelPackages;
-  interfaceName = "wt0";
-in {
-  meta.maintainers = with maintainers; [ misuzu ];
+
+  cfg = config.services.netbird;
+in
+{
+  meta.maintainers = with maintainers; [
+    misuzu
+    thubrecht
+  ];
+  meta.doc = ./netbird.md;
 
   options.services.netbird = {
     enable = mkEnableOption (lib.mdDoc "Netbird daemon");
     package = mkPackageOption pkgs "netbird" { };
-  };
-
-  config = mkIf cfg.enable {
-    boot.extraModulePackages = optional (versionOlder kernel.kernel.version "5.6") kernel.wireguard;
 
-    environment.systemPackages = [ cfg.package ];
+    tunnels = mkOption {
+      type = attrsOf (
+        submodule (
+          { name, config, ... }:
+          {
+            options = {
+              port = mkOption {
+                type = port;
+                default = 51820;
+                description = ''
+                  Port for the ${name} netbird interface.
+                '';
+              };
 
-    networking.dhcpcd.denyInterfaces = [ interfaceName ];
+              environment = mkOption {
+                type = attrsOf str;
+                defaultText = literalExpression ''
+                  {
+                    NB_CONFIG = "/var/lib/''${stateDir}/config.json";
+                    NB_LOG_FILE = "console";
+                    NB_WIREGUARD_PORT = builtins.toString port;
+                    NB_INTERFACE_NAME = name;
+                    NB_DAMEON_ADDR = "/var/run/''${stateDir}"
+                  }
+                '';
+                description = ''
+                  Environment for the netbird service, used to pass configuration options.
+                '';
+              };
 
-    systemd.network.networks."50-netbird" = mkIf config.networking.useNetworkd {
-      matchConfig = {
-        Name = interfaceName;
-      };
-      linkConfig = {
-        Unmanaged = true;
-        ActivationPolicy = "manual";
-      };
-    };
+              stateDir = mkOption {
+                type = str;
+                default = "netbird-${name}";
+                description = ''
+                  Directory storing the netbird configuration.
+                '';
+              };
+            };
 
-    systemd.services.netbird = {
-      description = "A WireGuard-based mesh network that connects your devices into a single private network";
-      documentation = [ "https://netbird.io/docs/" ];
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-      path = with pkgs; [
-        openresolv
-      ];
-      serviceConfig = {
-        Environment = [
-          "NB_CONFIG=/var/lib/netbird/config.json"
-          "NB_LOG_FILE=console"
-        ];
-        ExecStart = "${cfg.package}/bin/netbird service run";
-        Restart = "always";
-        RuntimeDirectory = "netbird";
-        StateDirectory = "netbird";
-        WorkingDirectory = "/var/lib/netbird";
-      };
-      unitConfig = {
-        StartLimitInterval = 5;
-        StartLimitBurst = 10;
-      };
-      stopIfChanged = false;
+            config.environment = builtins.mapAttrs (_: mkDefault) {
+              NB_CONFIG = "/var/lib/${config.stateDir}/config.json";
+              NB_LOG_FILE = "console";
+              NB_WIREGUARD_PORT = builtins.toString config.port;
+              NB_INTERFACE_NAME = name;
+              NB_DAEMON_ADDR = "unix:///var/run/${config.stateDir}/sock";
+            };
+          }
+        )
+      );
+      default = { };
+      description = ''
+        Attribute set of Netbird tunnels, each one will spawn a daemon listening on ...
+      '';
     };
   };
+
+  config = mkMerge [
+    (mkIf cfg.enable {
+      # For backwards compatibility
+      services.netbird.tunnels.wt0.stateDir = "netbird";
+    })
+
+    (mkIf (cfg.tunnels != { }) {
+      boot.extraModulePackages = optional (versionOlder kernel.kernel.version "5.6") kernel.wireguard;
+
+      environment.systemPackages = [ cfg.package ];
+
+      networking.dhcpcd.denyInterfaces = attrNames cfg.tunnels;
+
+      systemd.network.networks = mkIf config.networking.useNetworkd (
+        mapAttrs'
+          (
+            name: _:
+            nameValuePair "50-netbird-${name}" {
+              matchConfig = {
+                Name = name;
+              };
+              linkConfig = {
+                Unmanaged = true;
+                ActivationPolicy = "manual";
+              };
+            }
+          )
+          cfg.tunnels
+      );
+
+      systemd.services =
+        mapAttrs'
+          (
+            name:
+            { environment, stateDir, ... }:
+            nameValuePair "netbird-${name}" {
+              description = "A WireGuard-based mesh network that connects your devices into a single private network";
+
+              documentation = [ "https://netbird.io/docs/" ];
+
+              after = [ "network.target" ];
+              wantedBy = [ "multi-user.target" ];
+
+              path = with pkgs; [ openresolv ];
+
+              inherit environment;
+
+              serviceConfig = {
+                ExecStart = "${getExe cfg.package} service run";
+                Restart = "always";
+                RuntimeDirectory = stateDir;
+                StateDirectory = stateDir;
+                StateDirectoryMode = "0700";
+                WorkingDirectory = "/var/lib/${stateDir}";
+              };
+
+              unitConfig = {
+                StartLimitInterval = 5;
+                StartLimitBurst = 10;
+              };
+
+              stopIfChanged = false;
+            }
+          )
+          cfg.tunnels;
+    })
+  ];
 }
diff --git a/nixpkgs/nixos/modules/services/networking/nftables.nix b/nixpkgs/nixos/modules/services/networking/nftables.nix
index 424d005dc0b5..2351ebf4b707 100644
--- a/nixpkgs/nixos/modules/services/networking/nftables.nix
+++ b/nixpkgs/nixos/modules/services/networking/nftables.nix
@@ -185,6 +185,19 @@ in
           can be loaded using "nft -f".  The ruleset is updated atomically.
         '';
     };
+
+    networking.nftables.flattenRulesetFile = mkOption {
+      type = types.bool;
+      default = false;
+      description = lib.mdDoc ''
+        Use `builtins.readFile` rather than `include` to handle {option}`networking.nftables.rulesetFile`. It is useful when you want to apply {option}`networking.nftables.preCheckRuleset` to {option}`networking.nftables.rulesetFile`.
+
+        ::: {.note}
+        It is expected that {option}`networking.nftables.rulesetFile` can be accessed from the build sandbox.
+        :::
+      '';
+    };
+
     networking.nftables.tables = mkOption {
       type = types.attrsOf (types.submodule tableSubmodule);
 
@@ -252,8 +265,10 @@ in
     networking.nftables.flushRuleset = mkDefault (versionOlder config.system.stateVersion "23.11" || (cfg.rulesetFile != null || cfg.ruleset != ""));
     systemd.services.nftables = {
       description = "nftables firewall";
-      before = [ "network-pre.target" ];
-      wants = [ "network-pre.target" ];
+      after = [ "sysinit.target" ];
+      before = [ "network-pre.target" "shutdown.target" ];
+      conflicts = [ "shutdown.target" ];
+      wants = [ "network-pre.target" "sysinit.target" ];
       wantedBy = [ "multi-user.target" ];
       reloadIfChanged = true;
       serviceConfig = let
@@ -293,9 +308,13 @@ in
               }
             '') enabledTables)}
             ${cfg.ruleset}
-            ${lib.optionalString (cfg.rulesetFile != null) ''
-              include "${cfg.rulesetFile}"
-            ''}
+            ${if cfg.rulesetFile != null then
+              if cfg.flattenRulesetFile then
+                builtins.readFile cfg.rulesetFile
+                else ''
+                  include "${cfg.rulesetFile}"
+                ''
+              else ""}
           '';
           checkPhase = lib.optionalString cfg.checkRuleset ''
             cp $out ruleset.conf
@@ -315,6 +334,7 @@ in
         ExecStop = [ deletionsScriptVar cleanupDeletionsScript ];
         StateDirectory = "nftables";
       };
+      unitConfig.DefaultDependencies = false;
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/networking/ocserv.nix b/nixpkgs/nixos/modules/services/networking/ocserv.nix
index 9548fd92dbda..3c61d56b893e 100644
--- a/nixpkgs/nixos/modules/services/networking/ocserv.nix
+++ b/nixpkgs/nixos/modules/services/networking/ocserv.nix
@@ -85,6 +85,7 @@ in
     systemd.services.ocserv = {
       description = "OpenConnect SSL VPN server";
       documentation = [ "man:ocserv(8)" ];
+      wants = [ "network-online.target" ];
       after = [ "dbus.service" "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
 
diff --git a/nixpkgs/nixos/modules/services/networking/pleroma.nix b/nixpkgs/nixos/modules/services/networking/pleroma.nix
index db0a61b83469..8470f5e9cbc0 100644
--- a/nixpkgs/nixos/modules/services/networking/pleroma.nix
+++ b/nixpkgs/nixos/modules/services/networking/pleroma.nix
@@ -92,6 +92,7 @@ in {
 
     systemd.services.pleroma = {
       description = "Pleroma social network";
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" "postgresql.service" ];
       wantedBy = [ "multi-user.target" ];
       restartTriggers = [ config.environment.etc."/pleroma/config.exs".source ];
diff --git a/nixpkgs/nixos/modules/services/networking/pyload.nix b/nixpkgs/nixos/modules/services/networking/pyload.nix
new file mode 100644
index 000000000000..93f8dd7d731a
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/pyload.nix
@@ -0,0 +1,166 @@
+{ config, lib, pkgs, utils, ... }:
+let
+  cfg = config.services.pyload;
+
+  stateDir = "/var/lib/pyload";
+in
+{
+  meta.maintainers = with lib.maintainers; [ ambroisie ];
+
+  options = with lib; {
+    services.pyload = {
+      enable = mkEnableOption "pyLoad download manager";
+
+      package = mkPackageOption pkgs "pyLoad" { default = [ "pyload-ng" ]; };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "localhost";
+        example = "0.0.0.0";
+        description = "Address to listen on for the web UI.";
+      };
+
+      port = mkOption {
+        type = types.port;
+        default = 8000;
+        example = 9876;
+        description = "Port to listen on for the web UI.";
+      };
+
+      downloadDirectory = mkOption {
+        type = types.path;
+        default = "${stateDir}/downloads";
+        example = "/mnt/downloads";
+        description = "Directory to store downloads.";
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "pyload";
+        description = "User under which pyLoad runs, and which owns the download directory.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "pyload";
+        description = "Group under which pyLoad runs, and which owns the download directory.";
+      };
+
+      credentialsFile = mkOption {
+        type = with types; nullOr path;
+        default = null;
+        example = "/run/secrets/pyload-credentials.env";
+        description = ''
+          File containing {env}`PYLOAD_DEFAULT_USERNAME` and
+          {env}`PYLOAD_DEFAULT_PASSWORD` in the format of an `EnvironmentFile=`,
+          as described by {manpage}`systemd.exec(5)`.
+
+          If not given, they default to the username/password combo of
+          pyload/pyload.
+        '';
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    systemd.tmpfiles.settings.pyload = {
+      ${cfg.downloadDirectory}.d = { inherit (cfg) user group; };
+    };
+
+    systemd.services.pyload = {
+      description = "pyLoad download manager";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      # NOTE: unlike what the documentation says, it looks like `HOME` is not
+      # defined with this service definition...
+      # Since pyload tries to do the equivalent of `cd ~`, it needs to be able
+      # to resolve $HOME, which fails when `RootDirectory` is set.
+      # FIXME: check if `SetLoginEnvironment` fixes this issue in version 255
+      environment = {
+        HOME = stateDir;
+        PYLOAD__WEBUI__HOST = cfg.listenAddress;
+        PYLOAD__WEBUI__PORT = builtins.toString cfg.port;
+      };
+
+      serviceConfig = {
+        ExecStart = utils.escapeSystemdExecArgs [
+          (lib.getExe cfg.package)
+          "--userdir"
+          "${stateDir}/config"
+          "--storagedir"
+          cfg.downloadDirectory
+        ];
+
+        User = cfg.user;
+        Group = cfg.group;
+
+        EnvironmentFile = lib.optional (cfg.credentialsFile != null) cfg.credentialsFile;
+
+        StateDirectory = "pyload";
+        WorkingDirectory = stateDir;
+        RuntimeDirectory = "pyload";
+        RuntimeDirectoryMode = "0700";
+        RootDirectory = "/run/pyload";
+        BindReadOnlyPaths = [
+          builtins.storeDir # Needed to run the python interpreter
+        ];
+        BindPaths = [
+          cfg.downloadDirectory
+        ];
+
+        # Hardening options
+        LockPersonality = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateMounts = true;
+        PrivateTmp = true;
+        PrivateUsers = true;
+        ProcSubset = "pid";
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        ProtectSystem = "strict";
+        RemoveIPC = true;
+        RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX";
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+        SystemCallFilter = [ "@system-service" "~@resources" "~@privileged" ];
+        UMask = "0002";
+        CapabilityBoundingSet = [
+          "~CAP_BLOCK_SUSPEND"
+          "~CAP_BPF"
+          "~CAP_CHOWN"
+          "~CAP_IPC_LOCK"
+          "~CAP_KILL"
+          "~CAP_LEASE"
+          "~CAP_LINUX_IMMUTABLE"
+          "~CAP_NET_ADMIN"
+          "~CAP_SYS_ADMIN"
+          "~CAP_SYS_BOOT"
+          "~CAP_SYS_CHROOT"
+          "~CAP_SYS_NICE"
+          "~CAP_SYS_PACCT"
+          "~CAP_SYS_PTRACE"
+          "~CAP_SYS_RESOURCE"
+          "~CAP_SYS_TTY_CONFIG"
+        ];
+      };
+    };
+
+    users.users.pyload = lib.mkIf (cfg.user == "pyload") {
+      isSystemUser = true;
+      group = cfg.group;
+      home = stateDir;
+    };
+
+    users.groups.pyload = lib.mkIf (cfg.group == "pyload") { };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/networking/rosenpass.nix b/nixpkgs/nixos/modules/services/networking/rosenpass.nix
index d2a264b83d67..487cb6f60142 100644
--- a/nixpkgs/nixos/modules/services/networking/rosenpass.nix
+++ b/nixpkgs/nixos/modules/services/networking/rosenpass.nix
@@ -208,6 +208,7 @@ in
       in
       rec {
         wantedBy = [ "multi-user.target" ];
+        wants = [ "network-online.target" ];
         after = [ "network-online.target" ];
         path = [ cfg.package pkgs.wireguard-tools ];
 
diff --git a/nixpkgs/nixos/modules/services/networking/rxe.nix b/nixpkgs/nixos/modules/services/networking/rxe.nix
index 7dbb4823b4bc..07437ed71195 100644
--- a/nixpkgs/nixos/modules/services/networking/rxe.nix
+++ b/nixpkgs/nixos/modules/services/networking/rxe.nix
@@ -33,7 +33,7 @@ in {
 
       wantedBy = [ "multi-user.target" ];
       after = [ "systemd-modules-load.service" "network-online.target" ];
-      wants = [ "network-pre.target" ];
+      wants = [ "network-pre.target" "network-online.target" ];
 
       serviceConfig = {
         Type = "oneshot";
diff --git a/nixpkgs/nixos/modules/services/networking/seafile.nix b/nixpkgs/nixos/modules/services/networking/seafile.nix
index 9caabc60c78f..b2d12234900a 100644
--- a/nixpkgs/nixos/modules/services/networking/seafile.nix
+++ b/nixpkgs/nixos/modules/services/networking/seafile.nix
@@ -32,7 +32,8 @@ let
   dataDir = "${seafRoot}/data";
   seahubDir = "${seafRoot}/seahub";
 
-in {
+in
+{
 
   ###### Interface
 
@@ -147,146 +148,151 @@ in {
       description = "Seafile components";
     };
 
-    systemd.services = let
-      securityOptions = {
-        ProtectHome = true;
-        PrivateUsers = true;
-        PrivateDevices = true;
-        ProtectClock = true;
-        ProtectHostname = true;
-        ProtectProc = "invisible";
-        ProtectKernelModules = true;
-        ProtectKernelTunables = true;
-        ProtectKernelLogs = true;
-        ProtectControlGroups = true;
-        RestrictNamespaces = true;
-        LockPersonality = true;
-        RestrictRealtime = true;
-        RestrictSUIDSGID = true;
-        MemoryDenyWriteExecute = true;
-        SystemCallArchitectures = "native";
-        RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" ];
-      };
-    in {
-      seaf-server = {
-        description = "Seafile server";
-        partOf = [ "seafile.target" ];
-        after = [ "network.target" ];
-        wantedBy = [ "seafile.target" ];
-        restartTriggers = [ ccnetConf seafileConf ];
-        path = [ pkgs.sqlite ];
-        serviceConfig = securityOptions // {
-          User = "seafile";
-          Group = "seafile";
-          DynamicUser = true;
-          StateDirectory = "seafile";
-          RuntimeDirectory = "seafile";
-          LogsDirectory = "seafile";
-          ConfigurationDirectory = "seafile";
-          ExecStart = ''
-            ${cfg.seafilePackage}/bin/seaf-server \
-            --foreground \
-            -F /etc/seafile \
-            -c ${ccnetDir} \
-            -d ${dataDir} \
-            -l /var/log/seafile/server.log \
-            -P /run/seafile/server.pid \
-            -p /run/seafile
-          '';
+    systemd.services =
+      let
+        securityOptions = {
+          ProtectHome = true;
+          PrivateUsers = true;
+          PrivateDevices = true;
+          ProtectClock = true;
+          ProtectHostname = true;
+          ProtectProc = "invisible";
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          ProtectKernelLogs = true;
+          ProtectControlGroups = true;
+          RestrictNamespaces = true;
+          LockPersonality = true;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+          MemoryDenyWriteExecute = true;
+          SystemCallArchitectures = "native";
+          RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" ];
         };
-        preStart = ''
-          if [ ! -f "${seafRoot}/server-setup" ]; then
-              mkdir -p ${dataDir}/library-template
-              mkdir -p ${ccnetDir}/{GroupMgr,misc,OrgMgr,PeerMgr}
-              sqlite3 ${ccnetDir}/GroupMgr/groupmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/groupmgr.sql"
-              sqlite3 ${ccnetDir}/misc/config.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/config.sql"
-              sqlite3 ${ccnetDir}/OrgMgr/orgmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/org.sql"
-              sqlite3 ${ccnetDir}/PeerMgr/usermgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/user.sql"
-              sqlite3 ${dataDir}/seafile.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/seafile.sql"
-              echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup
-          fi
-          # checking for upgrades and handling them
-          # WARNING: needs to be extended to actually handle major version migrations
-          installedMajor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f1)
-          installedMinor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f2)
-          pkgMajor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f1)
-          pkgMinor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f2)
-
-          if [[ $installedMajor == $pkgMajor && $installedMinor == $pkgMinor ]]; then
-             :
-          elif [[ $installedMajor == 8 && $installedMinor == 0 && $pkgMajor == 9 && $pkgMinor == 0 ]]; then
-              # Upgrade from 8.0 to 9.0
-              sqlite3 ${dataDir}/seafile.db ".read ${pkgs.seahub}/scripts/upgrade/sql/9.0.0/sqlite3/seafile.sql"
-              echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup
-          else
-              echo "Unsupported upgrade" >&2
-              exit 1
-          fi
-        '';
-      };
+      in
+      {
+        seaf-server = {
+          description = "Seafile server";
+          partOf = [ "seafile.target" ];
+          after = [ "network.target" ];
+          wantedBy = [ "seafile.target" ];
+          restartTriggers = [ ccnetConf seafileConf ];
+          path = [ pkgs.sqlite ];
+          serviceConfig = securityOptions // {
+            User = "seafile";
+            Group = "seafile";
+            DynamicUser = true;
+            StateDirectory = "seafile";
+            RuntimeDirectory = "seafile";
+            LogsDirectory = "seafile";
+            ConfigurationDirectory = "seafile";
+            ExecStart = ''
+              ${cfg.seafilePackage}/bin/seaf-server \
+              --foreground \
+              -F /etc/seafile \
+              -c ${ccnetDir} \
+              -d ${dataDir} \
+              -l /var/log/seafile/server.log \
+              -P /run/seafile/server.pid \
+              -p /run/seafile
+            '';
+          };
+          preStart = ''
+            if [ ! -f "${seafRoot}/server-setup" ]; then
+                mkdir -p ${dataDir}/library-template
+                mkdir -p ${ccnetDir}/{GroupMgr,misc,OrgMgr,PeerMgr}
+                sqlite3 ${ccnetDir}/GroupMgr/groupmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/groupmgr.sql"
+                sqlite3 ${ccnetDir}/misc/config.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/config.sql"
+                sqlite3 ${ccnetDir}/OrgMgr/orgmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/org.sql"
+                sqlite3 ${ccnetDir}/PeerMgr/usermgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/user.sql"
+                sqlite3 ${dataDir}/seafile.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/seafile.sql"
+                echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup
+            fi
+            # checking for upgrades and handling them
+            installedMajor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f1)
+            installedMinor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f2)
+            pkgMajor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f1)
+            pkgMinor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f2)
 
-      seahub = {
-        description = "Seafile Server Web Frontend";
-        wantedBy = [ "seafile.target" ];
-        partOf = [ "seafile.target" ];
-        after = [ "network.target" "seaf-server.service" ];
-        requires = [ "seaf-server.service" ];
-        restartTriggers = [ seahubSettings ];
-        environment = {
-          PYTHONPATH = "${pkgs.seahub.pythonPath}:${pkgs.seahub}/thirdpart:${pkgs.seahub}";
-          DJANGO_SETTINGS_MODULE = "seahub.settings";
-          CCNET_CONF_DIR = ccnetDir;
-          SEAFILE_CONF_DIR = dataDir;
-          SEAFILE_CENTRAL_CONF_DIR = "/etc/seafile";
-          SEAFILE_RPC_PIPE_PATH = "/run/seafile";
-          SEAHUB_LOG_DIR = "/var/log/seafile";
+            if [[ $installedMajor == $pkgMajor && $installedMinor == $pkgMinor ]]; then
+               :
+            elif [[ $installedMajor == 8 && $installedMinor == 0 && $pkgMajor == 9 && $pkgMinor == 0 ]]; then
+                # Upgrade from 8.0 to 9.0
+                sqlite3 ${dataDir}/seafile.db ".read ${pkgs.seahub}/scripts/upgrade/sql/9.0.0/sqlite3/seafile.sql"
+                echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup
+            elif [[ $installedMajor == 9 && $installedMinor == 0 && $pkgMajor == 10 && $pkgMinor == 0 ]]; then
+                # Upgrade from 9.0 to 10.0
+                sqlite3 ${dataDir}/seafile.db ".read ${pkgs.seahub}/scripts/upgrade/sql/10.0.0/sqlite3/seafile.sql"
+                echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup
+            else
+                echo "Unsupported upgrade" >&2
+                exit 1
+            fi
+          '';
         };
-        serviceConfig = securityOptions // {
-          User = "seafile";
-          Group = "seafile";
-          DynamicUser = true;
-          RuntimeDirectory = "seahub";
-          StateDirectory = "seafile";
-          LogsDirectory = "seafile";
-          ConfigurationDirectory = "seafile";
-          ExecStart = ''
-            ${pkgs.seahub.python.pkgs.gunicorn}/bin/gunicorn seahub.wsgi:application \
-            --name seahub \
-            --workers ${toString cfg.workers} \
-            --log-level=info \
-            --preload \
-            --timeout=1200 \
-            --limit-request-line=8190 \
-            --bind unix:/run/seahub/gunicorn.sock
+
+        seahub = {
+          description = "Seafile Server Web Frontend";
+          wantedBy = [ "seafile.target" ];
+          partOf = [ "seafile.target" ];
+          after = [ "network.target" "seaf-server.service" ];
+          requires = [ "seaf-server.service" ];
+          restartTriggers = [ seahubSettings ];
+          environment = {
+            PYTHONPATH = "${pkgs.seahub.pythonPath}:${pkgs.seahub}/thirdpart:${pkgs.seahub}";
+            DJANGO_SETTINGS_MODULE = "seahub.settings";
+            CCNET_CONF_DIR = ccnetDir;
+            SEAFILE_CONF_DIR = dataDir;
+            SEAFILE_CENTRAL_CONF_DIR = "/etc/seafile";
+            SEAFILE_RPC_PIPE_PATH = "/run/seafile";
+            SEAHUB_LOG_DIR = "/var/log/seafile";
+          };
+          serviceConfig = securityOptions // {
+            User = "seafile";
+            Group = "seafile";
+            DynamicUser = true;
+            RuntimeDirectory = "seahub";
+            StateDirectory = "seafile";
+            LogsDirectory = "seafile";
+            ConfigurationDirectory = "seafile";
+            ExecStart = ''
+              ${pkgs.seahub.python.pkgs.gunicorn}/bin/gunicorn seahub.wsgi:application \
+              --name seahub \
+              --workers ${toString cfg.workers} \
+              --log-level=info \
+              --preload \
+              --timeout=1200 \
+              --limit-request-line=8190 \
+              --bind unix:/run/seahub/gunicorn.sock
+            '';
+          };
+          preStart = ''
+            mkdir -p ${seahubDir}/media
+            # Link all media except avatars
+            for m in `find ${pkgs.seahub}/media/ -maxdepth 1 -not -name "avatars"`; do
+              ln -sf $m ${seahubDir}/media/
+            done
+            if [ ! -e "${seafRoot}/.seahubSecret" ]; then
+                ${pkgs.seahub.python}/bin/python ${pkgs.seahub}/tools/secret_key_generator.py > ${seafRoot}/.seahubSecret
+                chmod 400 ${seafRoot}/.seahubSecret
+            fi
+            if [ ! -f "${seafRoot}/seahub-setup" ]; then
+                # avatars directory should be writable
+                install -D -t ${seahubDir}/media/avatars/ ${pkgs.seahub}/media/avatars/default.png
+                install -D -t ${seahubDir}/media/avatars/groups ${pkgs.seahub}/media/avatars/groups/default.png
+                # init database
+                ${pkgs.seahub}/manage.py migrate
+                # create admin account
+                ${pkgs.expect}/bin/expect -c 'spawn ${pkgs.seahub}/manage.py createsuperuser --email=${cfg.adminEmail}; expect "Password: "; send "${cfg.initialAdminPassword}\r"; expect "Password (again): "; send "${cfg.initialAdminPassword}\r"; expect "Superuser created successfully."'
+                echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup"
+            fi
+            if [ $(cat "${seafRoot}/seahub-setup" | cut -d"-" -f1) != "${pkgs.seahub.version}" ]; then
+                # update database
+                ${pkgs.seahub}/manage.py migrate
+                echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup"
+            fi
           '';
         };
-        preStart = ''
-          mkdir -p ${seahubDir}/media
-          # Link all media except avatars
-          for m in `find ${pkgs.seahub}/media/ -maxdepth 1 -not -name "avatars"`; do
-            ln -sf $m ${seahubDir}/media/
-          done
-          if [ ! -e "${seafRoot}/.seahubSecret" ]; then
-              ${pkgs.seahub.python}/bin/python ${pkgs.seahub}/tools/secret_key_generator.py > ${seafRoot}/.seahubSecret
-              chmod 400 ${seafRoot}/.seahubSecret
-          fi
-          if [ ! -f "${seafRoot}/seahub-setup" ]; then
-              # avatars directory should be writable
-              install -D -t ${seahubDir}/media/avatars/ ${pkgs.seahub}/media/avatars/default.png
-              install -D -t ${seahubDir}/media/avatars/groups ${pkgs.seahub}/media/avatars/groups/default.png
-              # init database
-              ${pkgs.seahub}/manage.py migrate
-              # create admin account
-              ${pkgs.expect}/bin/expect -c 'spawn ${pkgs.seahub}/manage.py createsuperuser --email=${cfg.adminEmail}; expect "Password: "; send "${cfg.initialAdminPassword}\r"; expect "Password (again): "; send "${cfg.initialAdminPassword}\r"; expect "Superuser created successfully."'
-              echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup"
-          fi
-          if [ $(cat "${seafRoot}/seahub-setup" | cut -d"-" -f1) != "${pkgs.seahub.version}" ]; then
-              # update database
-              ${pkgs.seahub}/manage.py migrate
-              echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup"
-          fi
-        '';
       };
-    };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/networking/soju.nix b/nixpkgs/nixos/modules/services/networking/soju.nix
index 7f0ac3e3b8e6..d69ec08ca13a 100644
--- a/nixpkgs/nixos/modules/services/networking/soju.nix
+++ b/nixpkgs/nixos/modules/services/networking/soju.nix
@@ -110,6 +110,7 @@ in
     systemd.services.soju = {
       description = "soju IRC bouncer";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       serviceConfig = {
         DynamicUser = true;
diff --git a/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix b/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix
index c8832ed4defb..c1f0aeb64e96 100644
--- a/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix
+++ b/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix
@@ -5,6 +5,9 @@ with (import ./param-lib.nix lib);
 
 let
   cfg = config.services.strongswan-swanctl;
+  configFile = pkgs.writeText "swanctl.conf"
+      ( (paramsToConf cfg.swanctl swanctlParams)
+      + (concatMapStrings (i: "\ninclude ${i}") cfg.includes));
   swanctlParams = import ./swanctl-params.nix lib;
 in  {
   options.services.strongswan-swanctl = {
@@ -21,6 +24,13 @@ in  {
     };
 
     swanctl = paramsToOptions swanctlParams;
+    includes = mkOption {
+      type = types.listOf types.path;
+      default = [];
+      description = ''
+        Extra configuration files to include in the swanctl configuration. This can be used to provide secret values from outside the nix store.
+      '';
+    };
   };
 
   config = mkIf cfg.enable {
@@ -31,8 +41,7 @@ in  {
       }
     ];
 
-    environment.etc."swanctl/swanctl.conf".text =
-      paramsToConf cfg.swanctl swanctlParams;
+    environment.etc."swanctl/swanctl.conf".source = configFile;
 
     # The swanctl command complains when the following directories don't exist:
     # See: https://wiki.strongswan.org/projects/strongswan/wiki/Swanctldirectory
@@ -55,6 +64,7 @@ in  {
     systemd.services.strongswan-swanctl = {
       description = "strongSwan IPsec IKEv1/IKEv2 daemon using swanctl";
       wantedBy = [ "multi-user.target" ];
+      wants    = [ "network-online.target" ];
       after    = [ "network-online.target" ];
       path     = with pkgs; [ kmod iproute2 iptables util-linux ];
       environment = {
diff --git a/nixpkgs/nixos/modules/services/networking/strongswan.nix b/nixpkgs/nixos/modules/services/networking/strongswan.nix
index e58526814d1a..dcf04d2a1917 100644
--- a/nixpkgs/nixos/modules/services/networking/strongswan.nix
+++ b/nixpkgs/nixos/modules/services/networking/strongswan.nix
@@ -153,6 +153,7 @@ in
       description = "strongSwan IPSec Service";
       wantedBy = [ "multi-user.target" ];
       path = with pkgs; [ kmod iproute2 iptables util-linux ]; # XXX Linux
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       environment = {
         STRONGSWAN_CONF = strongswanConf { inherit setup connections ca secretsFile managePlugins enabledPlugins; };
diff --git a/nixpkgs/nixos/modules/services/networking/syncplay.nix b/nixpkgs/nixos/modules/services/networking/syncplay.nix
index 0a66d93bf153..151259b6d4ad 100644
--- a/nixpkgs/nixos/modules/services/networking/syncplay.nix
+++ b/nixpkgs/nixos/modules/services/networking/syncplay.nix
@@ -107,6 +107,7 @@ in
     systemd.services.syncplay = {
       description = "Syncplay Service";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
 
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/networking/tailscale.nix b/nixpkgs/nixos/modules/services/networking/tailscale.nix
index 1070e4e25296..f11fe57d6ce5 100644
--- a/nixpkgs/nixos/modules/services/networking/tailscale.nix
+++ b/nixpkgs/nixos/modules/services/networking/tailscale.nix
@@ -74,11 +74,10 @@ in {
     systemd.services.tailscaled = {
       wantedBy = [ "multi-user.target" ];
       path = [
-        config.networking.resolvconf.package # for configuring DNS in some configs
         pkgs.procps     # for collecting running services (opt-in feature)
         pkgs.getent     # for `getent` to look up user shells
         pkgs.kmod       # required to pass tailscale's v6nat check
-      ];
+      ] ++ lib.optional config.networking.resolvconf.enable config.networking.resolvconf.package;
       serviceConfig.Environment = [
         "PORT=${toString cfg.port}"
         ''"FLAGS=--tun ${lib.escapeShellArg cfg.interfaceName}"''
diff --git a/nixpkgs/nixos/modules/services/networking/wasabibackend.nix b/nixpkgs/nixos/modules/services/networking/wasabibackend.nix
index 938145b35ee8..e3a48afd2a2c 100644
--- a/nixpkgs/nixos/modules/services/networking/wasabibackend.nix
+++ b/nixpkgs/nixos/modules/services/networking/wasabibackend.nix
@@ -119,6 +119,7 @@ in {
     systemd.services.wasabibackend = {
       description = "wasabibackend server";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       environment = {
         DOTNET_PRINT_TELEMETRY_MESSAGE = "false";
diff --git a/nixpkgs/nixos/modules/services/networking/znc/default.nix b/nixpkgs/nixos/modules/services/networking/znc/default.nix
index d3ba4a524197..e15233293cf2 100644
--- a/nixpkgs/nixos/modules/services/networking/znc/default.nix
+++ b/nixpkgs/nixos/modules/services/networking/znc/default.nix
@@ -243,6 +243,7 @@ in
     systemd.services.znc = {
       description = "ZNC Server";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       serviceConfig = {
         User = cfg.user;
diff --git a/nixpkgs/nixos/modules/services/security/bitwarden-directory-connector-cli.nix b/nixpkgs/nixos/modules/services/security/bitwarden-directory-connector-cli.nix
index 18c02e22fd7e..a55758322a75 100644
--- a/nixpkgs/nixos/modules/services/security/bitwarden-directory-connector-cli.nix
+++ b/nixpkgs/nixos/modules/services/security/bitwarden-directory-connector-cli.nix
@@ -277,42 +277,42 @@ in {
           BITWARDENCLI_CONNECTOR_PLAINTEXT_SECRETS = "true";
         };
 
+        preStart = ''
+          set -eo pipefail
+
+          # create the config file
+          ${lib.getExe cfg.package} data-file
+          touch /tmp/data.json.tmp
+          chmod 600 /tmp/data.json{,.tmp}
+
+          ${lib.getExe cfg.package} config server ${cfg.domain}
+
+          # now login to set credentials
+          export BW_CLIENTID="$(< ${escapeShellArg cfg.secrets.bitwarden.client_path_id})"
+          export BW_CLIENTSECRET="$(< ${escapeShellArg cfg.secrets.bitwarden.client_path_secret})"
+          ${lib.getExe cfg.package} login
+
+          jq '.authenticatedAccounts[0] as $account
+            | .[$account].directoryConfigurations.ldap |= $ldap_data
+            | .[$account].directorySettings.organizationId |= $orgID
+            | .[$account].directorySettings.sync |= $sync_data' \
+            --argjson ldap_data ${escapeShellArg cfg.ldap.finalJSON} \
+            --arg orgID "''${BW_CLIENTID//organization.}" \
+            --argjson sync_data ${escapeShellArg cfg.sync.finalJSON} \
+            /tmp/data.json \
+            > /tmp/data.json.tmp
+
+          mv -f /tmp/data.json.tmp /tmp/data.json
+
+          # final config
+          ${lib.getExe cfg.package} config directory 0
+          ${lib.getExe cfg.package} config ldap.password --secretfile ${cfg.secrets.ldap}
+        '';
+
         serviceConfig = {
           Type = "oneshot";
           User = "${cfg.user}";
           PrivateTmp = true;
-          preStart = ''
-            set -eo pipefail
-
-            # create the config file
-            ${lib.getExe cfg.package} data-file
-            touch /tmp/data.json.tmp
-            chmod 600 /tmp/data.json{,.tmp}
-
-            ${lib.getExe cfg.package} config server ${cfg.domain}
-
-            # now login to set credentials
-            export BW_CLIENTID="$(< ${escapeShellArg cfg.secrets.bitwarden.client_path_id})"
-            export BW_CLIENTSECRET="$(< ${escapeShellArg cfg.secrets.bitwarden.client_path_secret})"
-            ${lib.getExe cfg.package} login
-
-            jq '.authenticatedAccounts[0] as $account
-              | .[$account].directoryConfigurations.ldap |= $ldap_data
-              | .[$account].directorySettings.organizationId |= $orgID
-              | .[$account].directorySettings.sync |= $sync_data' \
-              --argjson ldap_data ${escapeShellArg cfg.ldap.finalJSON} \
-              --arg orgID "''${BW_CLIENTID//organization.}" \
-              --argjson sync_data ${escapeShellArg cfg.sync.finalJSON} \
-              /tmp/data.json \
-              > /tmp/data.json.tmp
-
-            mv -f /tmp/data.json.tmp /tmp/data.json
-
-            # final config
-            ${lib.getExe cfg.package} config directory 0
-            ${lib.getExe cfg.package} config ldap.password --secretfile ${cfg.secrets.ldap}
-          '';
-
           ExecStart = "${lib.getExe cfg.package} sync";
         };
       };
diff --git a/nixpkgs/nixos/modules/services/security/certmgr.nix b/nixpkgs/nixos/modules/services/security/certmgr.nix
index db80e943973d..02cb7afe87ba 100644
--- a/nixpkgs/nixos/modules/services/security/certmgr.nix
+++ b/nixpkgs/nixos/modules/services/security/certmgr.nix
@@ -182,6 +182,7 @@ in
     systemd.services.certmgr = {
       description = "certmgr";
       path = mkIf (cfg.svcManager == "command") [ pkgs.bash ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
       inherit preStart;
diff --git a/nixpkgs/nixos/modules/services/security/clamav.nix b/nixpkgs/nixos/modules/services/security/clamav.nix
index d3164373ec01..4480c0cae60c 100644
--- a/nixpkgs/nixos/modules/services/security/clamav.nix
+++ b/nixpkgs/nixos/modules/services/security/clamav.nix
@@ -196,6 +196,7 @@ in
     systemd.services.clamav-freshclam = mkIf cfg.updater.enable {
       description = "ClamAV virus database updater (freshclam)";
       restartTriggers = [ freshclamConfigFile ];
+      requires = [ "network-online.target" ];
       after = [ "network-online.target" ];
 
       serviceConfig = {
@@ -243,6 +244,7 @@ in
     systemd.services.clamav-fangfrisch = mkIf cfg.fangfrisch.enable {
       description = "ClamAV virus database updater (fangfrisch)";
       restartTriggers = [ fangfrischConfigFile ];
+      requires = [ "network-online.target" ];
       after = [ "network-online.target" "clamav-fangfrisch-init.service" ];
 
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/security/intune.nix b/nixpkgs/nixos/modules/services/security/intune.nix
new file mode 100644
index 000000000000..93cecaca5f43
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/security/intune.nix
@@ -0,0 +1,32 @@
+{ config
+, pkgs
+, lib
+, ...
+}:
+let
+  cfg = config.services.intune;
+in
+{
+  options.services.intune = {
+    enable = lib.mkEnableOption (lib.mdDoc "Microsoft Intune");
+  };
+
+
+  config = lib.mkIf cfg.enable {
+    users.users.microsoft-identity-broker = {
+      group = "microsoft-identity-broker";
+      isSystemUser = true;
+    };
+
+    users.groups.microsoft-identity-broker = { };
+    environment.systemPackages = [ pkgs.microsoft-identity-broker pkgs.intune-portal ];
+    systemd.packages = [ pkgs.microsoft-identity-broker pkgs.intune-portal ];
+
+    systemd.tmpfiles.packages = [ pkgs.intune-portal ];
+    services.dbus.packages = [ pkgs.microsoft-identity-broker ];
+  };
+
+  meta = {
+    maintainers = with lib.maintainers; [ rhysmdnz ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/security/kanidm.nix b/nixpkgs/nixos/modules/services/security/kanidm.nix
index c8d8f69729e9..c659d93b4087 100644
--- a/nixpkgs/nixos/modules/services/security/kanidm.nix
+++ b/nixpkgs/nixos/modules/services/security/kanidm.nix
@@ -165,10 +165,17 @@ in
       type = lib.types.submodule {
         freeformType = settingsFormat.type;
 
-        options.pam_allowed_login_groups = lib.mkOption {
-          description = lib.mdDoc "Kanidm groups that are allowed to login using PAM.";
-          example = "my_pam_group";
-          type = lib.types.listOf lib.types.str;
+        options = {
+          pam_allowed_login_groups = lib.mkOption {
+            description = lib.mdDoc "Kanidm groups that are allowed to login using PAM.";
+            example = "my_pam_group";
+            type = lib.types.listOf lib.types.str;
+          };
+          hsm_pin_path = lib.mkOption {
+            description = lib.mdDoc "Path to a HSM pin.";
+            default = "/var/cache/kanidm-unixd/hsm-pin";
+            type = lib.types.path;
+          };
         };
       };
       description = lib.mdDoc ''
diff --git a/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix b/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix
index 78916c907279..d1dc37d549d2 100644
--- a/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix
+++ b/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix
@@ -572,6 +572,7 @@ in
       description = "OAuth2 Proxy";
       path = [ cfg.package ];
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
 
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/system/cachix-agent/default.nix b/nixpkgs/nixos/modules/services/system/cachix-agent/default.nix
index 196d3291d555..f8020fe970f1 100644
--- a/nixpkgs/nixos/modules/services/system/cachix-agent/default.nix
+++ b/nixpkgs/nixos/modules/services/system/cachix-agent/default.nix
@@ -49,6 +49,7 @@ in {
   config = mkIf cfg.enable {
     systemd.services.cachix-agent = {
       description = "Cachix Deploy Agent";
+      wants = [ "network-online.target" ];
       after = ["network-online.target"];
       path = [ config.nix.package ];
       wantedBy = [ "multi-user.target" ];
diff --git a/nixpkgs/nixos/modules/services/system/cachix-watch-store.nix b/nixpkgs/nixos/modules/services/system/cachix-watch-store.nix
index 8aa5f0358fa9..d48af29465aa 100644
--- a/nixpkgs/nixos/modules/services/system/cachix-watch-store.nix
+++ b/nixpkgs/nixos/modules/services/system/cachix-watch-store.nix
@@ -61,6 +61,7 @@ in
   config = mkIf cfg.enable {
     systemd.services.cachix-watch-store-agent = {
       description = "Cachix watch store Agent";
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       path = [ config.nix.package ];
       wantedBy = [ "multi-user.target" ];
diff --git a/nixpkgs/nixos/modules/services/system/cloud-init.nix b/nixpkgs/nixos/modules/services/system/cloud-init.nix
index d782bb1a3666..00ae77be4271 100644
--- a/nixpkgs/nixos/modules/services/system/cloud-init.nix
+++ b/nixpkgs/nixos/modules/services/system/cloud-init.nix
@@ -164,7 +164,10 @@ in
     systemd.services.cloud-init-local = {
       description = "Initial cloud-init job (pre-networking)";
       wantedBy = [ "multi-user.target" ];
-      before = [ "systemd-networkd.service" ];
+      # In certain environments (AWS for example), cloud-init-local will
+      # first configure an IP through DHCP, and later delete it.
+      # This can cause race conditions with anything else trying to set IP through DHCP.
+      before = [ "systemd-networkd.service" "dhcpcd.service" ];
       path = path;
       serviceConfig = {
         Type = "oneshot";
diff --git a/nixpkgs/nixos/modules/services/system/dbus.nix b/nixpkgs/nixos/modules/services/system/dbus.nix
index b47ebc92f93a..e8f8b48d0337 100644
--- a/nixpkgs/nixos/modules/services/system/dbus.nix
+++ b/nixpkgs/nixos/modules/services/system/dbus.nix
@@ -95,6 +95,7 @@ in
         uid = config.ids.uids.messagebus;
         description = "D-Bus system message bus daemon user";
         home = homeDir;
+        homeMode = "0755";
         group = "messagebus";
       };
 
diff --git a/nixpkgs/nixos/modules/services/system/systemd-lock-handler.md b/nixpkgs/nixos/modules/services/system/systemd-lock-handler.md
new file mode 100644
index 000000000000..ac9ee00ae4bc
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/system/systemd-lock-handler.md
@@ -0,0 +1,47 @@
+# systemd-lock-handler {#module-services-systemd-lock-handler}
+
+The `systemd-lock-handler` module provides a service that bridges
+D-Bus events from `logind` to user-level systemd targets:
+
+  - `lock.target` started by `loginctl lock-session`,
+  - `unlock.target` started by `loginctl unlock-session` and
+  - `sleep.target` started by `systemctl suspend`.
+
+You can create a user service that starts with any of these targets.
+
+For example, to create a service for `swaylock`:
+
+```nix
+{
+  services.systemd-lock-handler.enable = true;
+
+  systemd.user.services.swaylock = {
+    description = "Screen locker for Wayland";
+    documentation = ["man:swaylock(1)"];
+
+    # If swaylock exits cleanly, unlock the session:
+    onSuccess = ["unlock.target"];
+
+    # When lock.target is stopped, stops this too:
+    partOf = ["lock.target"];
+
+    # Delay lock.target until this service is ready:
+    before = ["lock.target"];
+    wantedBy = ["lock.target"];
+
+    serviceConfig = {
+      # systemd will consider this service started when swaylock forks...
+      Type = "forking";
+
+      # ... and swaylock will fork only after it has locked the screen.
+      ExecStart = "${lib.getExe pkgs.swaylock} -f";
+
+      # If swaylock crashes, always restart it immediately:
+      Restart = "on-failure";
+      RestartSec = 0;
+    };
+  };
+}
+```
+
+See [upstream documentation](https://sr.ht/~whynothugo/systemd-lock-handler) for more information.
diff --git a/nixpkgs/nixos/modules/services/system/systemd-lock-handler.nix b/nixpkgs/nixos/modules/services/system/systemd-lock-handler.nix
new file mode 100644
index 000000000000..1ecb13b75bb3
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/system/systemd-lock-handler.nix
@@ -0,0 +1,27 @@
+{ config
+, pkgs
+, lib
+, ...
+}:
+let
+  cfg = config.services.systemd-lock-handler;
+  inherit (lib) mkIf mkEnableOption mkPackageOption;
+in
+{
+  options.services.systemd-lock-handler = {
+    enable = mkEnableOption (lib.mdDoc "systemd-lock-handler");
+    package = mkPackageOption pkgs "systemd-lock-handler" { };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.packages = [ cfg.package ];
+
+    # https://github.com/NixOS/nixpkgs/issues/81138
+    systemd.user.services.systemd-lock-handler.wantedBy = [ "default.target" ];
+  };
+
+  meta = {
+    maintainers = with lib.maintainers; [ liff ];
+    doc = ./systemd-lock-handler.md;
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/torrent/deluge.nix b/nixpkgs/nixos/modules/services/torrent/deluge.nix
index 4802e3e1c63a..632d8aa98aa2 100644
--- a/nixpkgs/nixos/modules/services/torrent/deluge.nix
+++ b/nixpkgs/nixos/modules/services/torrent/deluge.nix
@@ -191,17 +191,25 @@ in {
     # Provide a default set of `extraPackages`.
     services.deluge.extraPackages = with pkgs; [ unzip gnutar xz bzip2 ];
 
-    systemd.tmpfiles.rules = [
-      "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group}"
-      "d '${cfg.dataDir}/.config' 0770 ${cfg.user} ${cfg.group}"
-      "d '${cfg.dataDir}/.config/deluge' 0770 ${cfg.user} ${cfg.group}"
-    ]
-    ++ optional (cfg.config ? download_location)
-      "d '${cfg.config.download_location}' 0770 ${cfg.user} ${cfg.group}"
-    ++ optional (cfg.config ? torrentfiles_location)
-      "d '${cfg.config.torrentfiles_location}' 0770 ${cfg.user} ${cfg.group}"
-    ++ optional (cfg.config ? move_completed_path)
-      "d '${cfg.config.move_completed_path}' 0770 ${cfg.user} ${cfg.group}";
+    systemd.tmpfiles.settings."10-deluged" = let
+      defaultConfig = {
+        inherit (cfg) user group;
+        mode = "0770";
+      };
+    in {
+      "${cfg.dataDir}".d = defaultConfig;
+      "${cfg.dataDir}/.config".d = defaultConfig;
+      "${cfg.dataDir}/.config/deluge".d = defaultConfig;
+    }
+    // optionalAttrs (cfg.config ? download_location) {
+      ${cfg.config.download_location}.d = defaultConfig;
+    }
+    // optionalAttrs (cfg.config ? torrentfiles_location) {
+      ${cfg.config.torrentfiles_location}.d = defaultConfig;
+    }
+    // optionalAttrs (cfg.config ? move_completed_path) {
+      ${cfg.config.move_completed_path}.d = defaultConfig;
+    };
 
     systemd.services.deluged = {
       after = [ "network.target" ];
diff --git a/nixpkgs/nixos/modules/services/video/epgstation/default.nix b/nixpkgs/nixos/modules/services/video/epgstation/default.nix
index a7468e7cc2b6..1b3258c3df8e 100644
--- a/nixpkgs/nixos/modules/services/video/epgstation/default.nix
+++ b/nixpkgs/nixos/modules/services/video/epgstation/default.nix
@@ -309,17 +309,25 @@ in
         (lib.mkIf cfg.usePreconfiguredStreaming streamingConfig)
       ];
 
-    systemd.tmpfiles.rules = [
-      "d '/var/lib/epgstation/key' - ${username} ${groupname} - -"
-      "d '/var/lib/epgstation/streamfiles' - ${username} ${groupname} - -"
-      "d '/var/lib/epgstation/drop' - ${username} ${groupname} - -"
-      "d '/var/lib/epgstation/recorded' - ${username} ${groupname} - -"
-      "d '/var/lib/epgstation/thumbnail' - ${username} ${groupname} - -"
-      "d '/var/lib/epgstation/db/subscribers' - ${username} ${groupname} - -"
-      "d '/var/lib/epgstation/db/migrations/mysql' - ${username} ${groupname} - -"
-      "d '/var/lib/epgstation/db/migrations/postgres' - ${username} ${groupname} - -"
-      "d '/var/lib/epgstation/db/migrations/sqlite' - ${username} ${groupname} - -"
-    ];
+    systemd.tmpfiles.settings."10-epgstation" =
+      lib.listToAttrs
+        (map (dir: lib.nameValuePair dir {
+          d = {
+            user = username;
+            group = groupname;
+          };
+        })
+        [
+          "/var/lib/epgstation/key"
+          "/var/lib/epgstation/streamfiles"
+          "/var/lib/epgstation/drop"
+          "/var/lib/epgstation/recorded"
+          "/var/lib/epgstation/thumbnail"
+          "/var/lib/epgstation/db/subscribers"
+          "/var/lib/epgstation/db/migrations/mysql"
+          "/var/lib/epgstation/db/migrations/postgres"
+          "/var/lib/epgstation/db/migrations/sqlite"
+        ]);
 
     systemd.services.epgstation = {
       inherit description;
diff --git a/nixpkgs/nixos/modules/services/video/frigate.nix b/nixpkgs/nixos/modules/services/video/frigate.nix
index b7945282ba09..0c923a20c40c 100644
--- a/nixpkgs/nixos/modules/services/video/frigate.nix
+++ b/nixpkgs/nixos/modules/services/video/frigate.nix
@@ -17,7 +17,7 @@ let
 
   cfg = config.services.frigate;
 
-  format = pkgs.formats.yaml {};
+  format = pkgs.formats.yaml { };
 
   filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! lib.elem v [ null ])) cfg.settings;
 
@@ -112,7 +112,7 @@ in
           };
         };
       };
-      default = {};
+      default = { };
       description = mdDoc ''
         Frigate configuration as a nix attribute set.
 
@@ -125,7 +125,7 @@ in
 
   config = mkIf cfg.enable {
     services.nginx = {
-      enable =true;
+      enable = true;
       additionalModules = with pkgs.nginxModules; [
         secure-token
         rtmp
@@ -133,31 +133,64 @@ in
       ];
       recommendedProxySettings = mkDefault true;
       recommendedGzipSettings = mkDefault true;
+      mapHashBucketSize = mkDefault 128;
       upstreams = {
         frigate-api.servers = {
-          "127.0.0.1:5001" = {};
+          "127.0.0.1:5001" = { };
         };
         frigate-mqtt-ws.servers = {
-          "127.0.0.1:5002" = {};
+          "127.0.0.1:5002" = { };
         };
         frigate-jsmpeg.servers = {
-          "127.0.0.1:8082" = {};
+          "127.0.0.1:8082" = { };
         };
         frigate-go2rtc.servers = {
-          "127.0.0.1:1984" = {};
+          "127.0.0.1:1984" = { };
         };
       };
-      # Based on https://github.com/blakeblackshear/frigate/blob/v0.12.0/docker/rootfs/usr/local/nginx/conf/nginx.conf
+      proxyCachePath."frigate" = {
+        enable = true;
+        keysZoneSize = "10m";
+        keysZoneName = "frigate_api_cache";
+        maxSize = "10m";
+        inactive = "1m";
+        levels = "1:2";
+      };
+      # Based on https://github.com/blakeblackshear/frigate/blob/v0.13.1/docker/main/rootfs/usr/local/nginx/conf/nginx.conf
       virtualHosts."${cfg.hostname}" = {
         locations = {
           "/api/" = {
             proxyPass = "http://frigate-api/";
+            extraConfig = ''
+              proxy_cache frigate_api_cache;
+              proxy_cache_lock on;
+              proxy_cache_use_stale updating;
+              proxy_cache_valid 200 5s;
+              proxy_cache_bypass $http_x_cache_bypass;
+              proxy_no_cache $should_not_cache;
+              add_header X-Cache-Status $upstream_cache_status;
+
+              location /api/vod/ {
+                  proxy_pass http://frigate-api/vod/;
+                  proxy_cache off;
+              }
+
+              location /api/stats {
+                  access_log off;
+                  rewrite ^/api/(.*)$ $1 break;
+                  proxy_pass http://frigate-api;
+              }
+
+              location /api/version {
+                  access_log off;
+                  rewrite ^/api/(.*)$ $1 break;
+                  proxy_pass http://frigate-api;
+              }
+            '';
           };
           "~* /api/.*\.(jpg|jpeg|png)$" = {
             proxyPass = "http://frigate-api";
             extraConfig = ''
-              add_header 'Access-Control-Allow-Origin' '*';
-              add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
               rewrite ^/api/(.*)$ $1 break;
             '';
           };
@@ -169,10 +202,6 @@ in
               secure_token $args;
               secure_token_types application/vnd.apple.mpegurl;
 
-              add_header Access-Control-Allow-Headers '*';
-              add_header Access-Control-Expose-Headers 'Server,range,Content-Length,Content-Range';
-              add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS';
-              add_header Access-Control-Allow-Origin '*';
               add_header Cache-Control "no-store";
               expires off;
             '';
@@ -192,27 +221,64 @@ in
             proxyPass = "http://frigate-go2rtc/";
             proxyWebsockets = true;
           };
+          # frigate lovelace card uses this path
+          "/live/mse/api/ws" = {
+            proxyPass = "http://frigate-go2rtc/api/ws";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
           "/live/webrtc/" = {
             proxyPass = "http://frigate-go2rtc/";
             proxyWebsockets = true;
           };
+          "/live/webrtc/api/ws" = {
+            proxyPass = "http://frigate-go2rtc/api/ws";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
+          # pass through go2rtc player
+          "/live/webrtc/webrtc.html" = {
+            proxyPass = "http://frigate-go2rtc/webrtc.html";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
+          "/api/go2rtc/api" = {
+            proxyPass = "http://frigate-go2rtc/api";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
+          # integrationn uses this to add webrtc candidate
+          "/api/go2rtc/webrtc" = {
+            proxyPass = "http://frigate-go2rtc/api/webrtc";
+            proxyWebsockets = true;
+            extraConfig = ''
+              limit_except GET {
+                  deny  all;
+              }
+            '';
+          };
           "/cache/" = {
             alias = "/var/cache/frigate/";
           };
           "/clips/" = {
             root = "/var/lib/frigate";
             extraConfig = ''
-              add_header 'Access-Control-Allow-Origin' "$http_origin" always;
-              add_header 'Access-Control-Allow-Credentials' 'true';
-              add_header 'Access-Control-Expose-Headers' 'Content-Length';
-              if ($request_method = 'OPTIONS') {
-                  add_header 'Access-Control-Allow-Origin' "$http_origin";
-                  add_header 'Access-Control-Max-Age' 1728000;
-                  add_header 'Content-Type' 'text/plain charset=UTF-8';
-                  add_header 'Content-Length' 0;
-                  return 204;
-              }
-
               types {
                   video/mp4 mp4;
                   image/jpeg jpg;
@@ -224,17 +290,6 @@ in
           "/recordings/" = {
             root = "/var/lib/frigate";
             extraConfig = ''
-              add_header 'Access-Control-Allow-Origin' "$http_origin" always;
-              add_header 'Access-Control-Allow-Credentials' 'true';
-              add_header 'Access-Control-Expose-Headers' 'Content-Length';
-              if ($request_method = 'OPTIONS') {
-                  add_header 'Access-Control-Allow-Origin' "$http_origin";
-                  add_header 'Access-Control-Max-Age' 1728000;
-                  add_header 'Content-Type' 'text/plain charset=UTF-8';
-                  add_header 'Content-Length' 0;
-                  return 204;
-              }
-
               types {
                   video/mp4 mp4;
               }
@@ -315,6 +370,12 @@ in
             }
         }
       '';
+      appendHttpConfig = ''
+        map $sent_http_content_type $should_not_cache {
+          'application/json' 0;
+          default 1;
+        }
+      '';
     };
 
     systemd.services.nginx.serviceConfig.SupplementaryGroups = [
@@ -325,7 +386,7 @@ in
       isSystemUser = true;
       group = "frigate";
     };
-    users.groups.frigate = {};
+    users.groups.frigate = { };
 
     systemd.services.frigate = {
       after = [
diff --git a/nixpkgs/nixos/modules/services/video/go2rtc/default.nix b/nixpkgs/nixos/modules/services/video/go2rtc/default.nix
index 13851fa0306f..9dddbb60baa8 100644
--- a/nixpkgs/nixos/modules/services/video/go2rtc/default.nix
+++ b/nixpkgs/nixos/modules/services/video/go2rtc/default.nix
@@ -94,6 +94,7 @@ in
 
   config = lib.mkIf cfg.enable {
     systemd.services.go2rtc = {
+      wants = [ "network-online.target" ];
       after = [
         "network-online.target"
       ];
diff --git a/nixpkgs/nixos/modules/services/video/mirakurun.nix b/nixpkgs/nixos/modules/services/video/mirakurun.nix
index 31f90650ba9a..208b34ab353a 100644
--- a/nixpkgs/nixos/modules/services/video/mirakurun.nix
+++ b/nixpkgs/nixos/modules/services/video/mirakurun.nix
@@ -165,9 +165,10 @@ in
         port = mkIf (cfg.port != null) cfg.port;
       };
 
-      systemd.tmpfiles.rules = [
-        "d '/etc/mirakurun' - ${username} ${groupname} - -"
-      ];
+      systemd.tmpfiles.settings."10-mirakurun"."/etc/mirakurun".d = {
+        user = username;
+        group = groupname;
+      };
 
       systemd.services.mirakurun = {
         description = mirakurun.meta.description;
diff --git a/nixpkgs/nixos/modules/services/web-apps/akkoma.nix b/nixpkgs/nixos/modules/services/web-apps/akkoma.nix
index 8980556ab014..4cd9e2664378 100644
--- a/nixpkgs/nixos/modules/services/web-apps/akkoma.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/akkoma.nix
@@ -974,7 +974,7 @@ in {
       # This service depends on network-online.target and is sequenced after
       # it because it requires access to the Internet to function properly.
       bindsTo = [ "akkoma-config.service" ];
-      wants = [ "network-online.service" ];
+      wants = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
       after = [
         "akkoma-config.target"
diff --git a/nixpkgs/nixos/modules/services/web-apps/alps.nix b/nixpkgs/nixos/modules/services/web-apps/alps.nix
index 05fb676102df..81c6b8ad30b5 100644
--- a/nixpkgs/nixos/modules/services/web-apps/alps.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/alps.nix
@@ -94,6 +94,7 @@ in {
       description = "alps is a simple and extensible webmail.";
       documentation = [ "https://git.sr.ht/~migadu/alps" ];
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network.target" "network-online.target" ];
 
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/web-apps/bookstack.nix b/nixpkgs/nixos/modules/services/web-apps/bookstack.nix
index d846c98577c8..4999eceb2b60 100644
--- a/nixpkgs/nixos/modules/services/web-apps/bookstack.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/bookstack.nix
@@ -412,20 +412,25 @@ in {
       '';
     };
 
-    systemd.tmpfiles.rules = [
-      "d ${cfg.dataDir}                            0710 ${user} ${group} - -"
-      "d ${cfg.dataDir}/public                     0750 ${user} ${group} - -"
-      "d ${cfg.dataDir}/public/uploads             0750 ${user} ${group} - -"
-      "d ${cfg.dataDir}/storage                    0700 ${user} ${group} - -"
-      "d ${cfg.dataDir}/storage/app                0700 ${user} ${group} - -"
-      "d ${cfg.dataDir}/storage/fonts              0700 ${user} ${group} - -"
-      "d ${cfg.dataDir}/storage/framework          0700 ${user} ${group} - -"
-      "d ${cfg.dataDir}/storage/framework/cache    0700 ${user} ${group} - -"
-      "d ${cfg.dataDir}/storage/framework/sessions 0700 ${user} ${group} - -"
-      "d ${cfg.dataDir}/storage/framework/views    0700 ${user} ${group} - -"
-      "d ${cfg.dataDir}/storage/logs               0700 ${user} ${group} - -"
-      "d ${cfg.dataDir}/storage/uploads            0700 ${user} ${group} - -"
-    ];
+    systemd.tmpfiles.settings."10-bookstack" = let
+      defaultConfig = {
+        inherit user group;
+        mode = "0700";
+      };
+    in {
+      "${cfg.dataDir}".d = defaultConfig // { mode = "0710"; };
+      "${cfg.dataDir}/public".d = defaultConfig // { mode = "0750"; };
+      "${cfg.dataDir}/public/uploads".d = defaultConfig // { mode = "0750"; };
+      "${cfg.dataDir}/storage".d = defaultConfig;
+      "${cfg.dataDir}/storage/app".d = defaultConfig;
+      "${cfg.dataDir}/storage/fonts".d = defaultConfig;
+      "${cfg.dataDir}/storage/framework".d = defaultConfig;
+      "${cfg.dataDir}/storage/framework/cache".d = defaultConfig;
+      "${cfg.dataDir}/storage/framework/sessions".d = defaultConfig;
+      "${cfg.dataDir}/storage/framework/views".d = defaultConfig;
+      "${cfg.dataDir}/storage/logs".d = defaultConfig;
+      "${cfg.dataDir}/storage/uploads".d = defaultConfig;
+    };
 
     users = {
       users = mkIf (user == "bookstack") {
diff --git a/nixpkgs/nixos/modules/services/web-apps/c2fmzq-server.nix b/nixpkgs/nixos/modules/services/web-apps/c2fmzq-server.nix
index 87938fe160e1..dee131182de1 100644
--- a/nixpkgs/nixos/modules/services/web-apps/c2fmzq-server.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/c2fmzq-server.nix
@@ -80,6 +80,7 @@ in {
       description = "c2FmZQ-server";
       documentation = [ "https://github.com/c2FmZQ/c2FmZQ/blob/main/README.md" ];
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network.target" "network-online.target" ];
 
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/web-apps/code-server.nix b/nixpkgs/nixos/modules/services/web-apps/code-server.nix
index 11601f6c3044..d087deb7848d 100644
--- a/nixpkgs/nixos/modules/services/web-apps/code-server.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/code-server.nix
@@ -205,6 +205,7 @@ in {
     systemd.services.code-server = {
       description = "Code server";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       path = cfg.extraPackages;
       environment = {
diff --git a/nixpkgs/nixos/modules/services/web-apps/freshrss.nix b/nixpkgs/nixos/modules/services/web-apps/freshrss.nix
index c8399143c37b..edec9d547a30 100644
--- a/nixpkgs/nixos/modules/services/web-apps/freshrss.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/freshrss.nix
@@ -228,9 +228,10 @@ in
       };
       users.groups."${cfg.user}" = { };
 
-      systemd.tmpfiles.rules = [
-        "d '${cfg.dataDir}' - ${cfg.user} ${config.users.users.${cfg.user}.group} - -"
-      ];
+      systemd.tmpfiles.settings."10-freshrss".${cfg.dataDir}.d = {
+        inherit (cfg) user;
+        group = config.users.users.${cfg.user}.group;
+      };
 
       systemd.services.freshrss-config =
         let
diff --git a/nixpkgs/nixos/modules/services/web-apps/healthchecks.nix b/nixpkgs/nixos/modules/services/web-apps/healthchecks.nix
index e5e425a29d54..1d439f162313 100644
--- a/nixpkgs/nixos/modules/services/web-apps/healthchecks.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/healthchecks.nix
@@ -176,6 +176,7 @@ in
     systemd.targets.healthchecks = {
       description = "Target for all Healthchecks services";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network.target" "network-online.target" ];
     };
 
diff --git a/nixpkgs/nixos/modules/services/web-apps/lemmy.nix b/nixpkgs/nixos/modules/services/web-apps/lemmy.nix
index bde9051a7033..968dcac93fab 100644
--- a/nixpkgs/nixos/modules/services/web-apps/lemmy.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/lemmy.nix
@@ -204,7 +204,6 @@ in
           };
           "/" = {
             # mixed frontend and backend requests, based on the request headers
-            proxyPass = "$proxpass";
             recommendedProxySettings = true;
             extraConfig = ''
               set $proxpass "${ui}";
@@ -220,6 +219,8 @@ in
 
               # Cuts off the trailing slash on URLs to make them valid
               rewrite ^(.+)/+$ $1 permanent;
+
+              proxy_pass $proxpass;
             '';
           };
         };
diff --git a/nixpkgs/nixos/modules/services/web-apps/mastodon.nix b/nixpkgs/nixos/modules/services/web-apps/mastodon.nix
index 538e728fcc72..8d09d1b97828 100644
--- a/nixpkgs/nixos/modules/services/web-apps/mastodon.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/mastodon.nix
@@ -133,6 +133,7 @@ let
         RestartSec = 20;
         EnvironmentFile = [ "/var/lib/mastodon/.secrets_env" ] ++ cfg.extraEnvFiles;
         WorkingDirectory = cfg.package;
+        LimitNOFILE = "1024000";
         # System Call Filtering
         SystemCallFilter = [ ("~" + lib.concatStringsSep " " systemCallsList) "@chown" "pipe" "pipe2" ];
       } // cfgService;
diff --git a/nixpkgs/nixos/modules/services/web-apps/mattermost.nix b/nixpkgs/nixos/modules/services/web-apps/mattermost.nix
index 503559432374..3d03c96d1c19 100644
--- a/nixpkgs/nixos/modules/services/web-apps/mattermost.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/mattermost.nix
@@ -277,9 +277,7 @@ in
 
       # The systemd service will fail to execute the preStart hook
       # if the WorkingDirectory does not exist
-      systemd.tmpfiles.rules = [
-        ''d "${cfg.statePath}" -''
-      ];
+      systemd.tmpfiles.settings."10-mattermost".${cfg.statePath}.d = { };
 
       systemd.services.mattermost = {
         description = "Mattermost chat service";
diff --git a/nixpkgs/nixos/modules/services/web-apps/moodle.nix b/nixpkgs/nixos/modules/services/web-apps/moodle.nix
index ce6a80054725..496a0e32436f 100644
--- a/nixpkgs/nixos/modules/services/web-apps/moodle.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/moodle.nix
@@ -255,9 +255,10 @@ in
       } ];
     };
 
-    systemd.tmpfiles.rules = [
-      "d '${stateDir}' 0750 ${user} ${group} - -"
-    ];
+    systemd.tmpfiles.settings."10-moodle".${stateDir}.d = {
+      inherit user group;
+      mode = "0750";
+    };
 
     systemd.services.moodle-init = {
       wantedBy = [ "multi-user.target" ];
diff --git a/nixpkgs/nixos/modules/services/web-apps/netbox.nix b/nixpkgs/nixos/modules/services/web-apps/netbox.nix
index 88d40b3abc52..d034f3234a2b 100644
--- a/nixpkgs/nixos/modules/services/web-apps/netbox.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/netbox.nix
@@ -75,13 +75,17 @@ in {
     package = lib.mkOption {
       type = lib.types.package;
       default =
-        if lib.versionAtLeast config.system.stateVersion "23.11"
+        if lib.versionAtLeast config.system.stateVersion "24.05"
+        then pkgs.netbox_3_7
+        else if lib.versionAtLeast config.system.stateVersion "23.11"
         then pkgs.netbox_3_6
         else if lib.versionAtLeast config.system.stateVersion "23.05"
         then pkgs.netbox_3_5
         else pkgs.netbox_3_3;
       defaultText = lib.literalExpression ''
-        if lib.versionAtLeast config.system.stateVersion "23.11"
+        if lib.versionAtLeast config.system.stateVersion "24.05"
+        then pkgs.netbox_3_7
+        else if lib.versionAtLeast config.system.stateVersion "23.11"
         then pkgs.netbox_3_6
         else if lib.versionAtLeast config.system.stateVersion "23.05"
         then pkgs.netbox_3_5
@@ -267,6 +271,7 @@ in {
     systemd.targets.netbox = {
       description = "Target for all NetBox services";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" "redis-netbox.service" ];
     };
 
@@ -305,12 +310,13 @@ in {
           ${pkg}/bin/netbox trace_paths --no-input
           ${pkg}/bin/netbox collectstatic --no-input
           ${pkg}/bin/netbox remove_stale_contenttypes --no-input
-          # TODO: remove the condition when we remove netbox_3_3
-          ${lib.optionalString
-            (lib.versionAtLeast cfg.package.version "3.5.0")
-            "${pkg}/bin/netbox reindex --lazy"}
+          ${pkg}/bin/netbox reindex --lazy
           ${pkg}/bin/netbox clearsessions
-          ${pkg}/bin/netbox clearcache
+          ${lib.optionalString
+            # The clearcache command was removed in 3.7.0:
+            # https://github.com/netbox-community/netbox/issues/14458
+            (lib.versionOlder cfg.package.version "3.7.0")
+            "${pkg}/bin/netbox clearcache"}
 
           echo "${cfg.package.version}" > "$versionFile"
         '';
diff --git a/nixpkgs/nixos/modules/services/web-apps/nextcloud-notify_push.nix b/nixpkgs/nixos/modules/services/web-apps/nextcloud-notify_push.nix
index 759daa0c50dc..7b90e0bbaa9b 100644
--- a/nixpkgs/nixos/modules/services/web-apps/nextcloud-notify_push.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/nextcloud-notify_push.nix
@@ -116,7 +116,7 @@ in
       }
 
       (lib.mkIf cfg.bendDomainToLocalhost {
-        nextcloud.extraOptions.trusted_proxies = [ "127.0.0.1" "::1" ];
+        nextcloud.settings.trusted_proxies = [ "127.0.0.1" "::1" ];
       })
     ];
   };
diff --git a/nixpkgs/nixos/modules/services/web-apps/nextcloud.md b/nixpkgs/nixos/modules/services/web-apps/nextcloud.md
index ce8f96a6a389..5db83d7e4463 100644
--- a/nixpkgs/nixos/modules/services/web-apps/nextcloud.md
+++ b/nixpkgs/nixos/modules/services/web-apps/nextcloud.md
@@ -51,7 +51,7 @@ to ensure that changes can be applied by changing the module's options.
 In case the application serves multiple domains (those are checked with
 [`$_SERVER['HTTP_HOST']`](https://www.php.net/manual/en/reserved.variables.server.php))
 it's needed to add them to
-[`services.nextcloud.extraOptions.trusted_domains`](#opt-services.nextcloud.extraOptions.trusted_domains).
+[`services.nextcloud.settings.trusted_domains`](#opt-services.nextcloud.settings.trusted_domains).
 
 Auto updates for Nextcloud apps can be enabled using
 [`services.nextcloud.autoUpdateApps`](#opt-services.nextcloud.autoUpdateApps.enable).
diff --git a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
index 38c51251aac1..08f90dcf59d8 100644
--- a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
@@ -99,11 +99,101 @@ let
   mysqlLocal = cfg.database.createLocally && cfg.config.dbtype == "mysql";
   pgsqlLocal = cfg.database.createLocally && cfg.config.dbtype == "pgsql";
 
+  nextcloudGreaterOrEqualThan = versionAtLeast cfg.package.version;
+  nextcloudOlderThan = versionOlder cfg.package.version;
+
   # https://github.com/nextcloud/documentation/pull/11179
-  ocmProviderIsNotAStaticDirAnymore = versionAtLeast cfg.package.version "27.1.2"
-    || (versionOlder cfg.package.version "27.0.0"
-      && versionAtLeast cfg.package.version "26.0.8");
+  ocmProviderIsNotAStaticDirAnymore = nextcloudGreaterOrEqualThan "27.1.2"
+    || (nextcloudOlderThan "27.0.0" && nextcloudGreaterOrEqualThan "26.0.8");
+
+  overrideConfig = let
+    c = cfg.config;
+    requiresReadSecretFunction = c.dbpassFile != null || c.objectstore.s3.enable;
+    objectstoreConfig = let s3 = c.objectstore.s3; in optionalString s3.enable ''
+      'objectstore' => [
+        'class' => '\\OC\\Files\\ObjectStore\\S3',
+        'arguments' => [
+          'bucket' => '${s3.bucket}',
+          'autocreate' => ${boolToString s3.autocreate},
+          'key' => '${s3.key}',
+          'secret' => nix_read_secret('${s3.secretFile}'),
+          ${optionalString (s3.hostname != null) "'hostname' => '${s3.hostname}',"}
+          ${optionalString (s3.port != null) "'port' => ${toString s3.port},"}
+          'use_ssl' => ${boolToString s3.useSsl},
+          ${optionalString (s3.region != null) "'region' => '${s3.region}',"}
+          'use_path_style' => ${boolToString s3.usePathStyle},
+          ${optionalString (s3.sseCKeyFile != null) "'sse_c_key' => nix_read_secret('${s3.sseCKeyFile}'),"}
+        ],
+      ]
+    '';
+    showAppStoreSetting = cfg.appstoreEnable != null || cfg.extraApps != {};
+    renderedAppStoreSetting =
+      let
+        x = cfg.appstoreEnable;
+      in
+        if x == null then "false"
+        else boolToString x;
+    mkAppStoreConfig = name: { enabled, writable, ... }: optionalString enabled ''
+      [ 'path' => '${webroot}/${name}', 'url' => '/${name}', 'writable' => ${boolToString writable} ],
+    '';
+  in pkgs.writeText "nextcloud-config.php" ''
+    <?php
+    ${optionalString requiresReadSecretFunction ''
+      function nix_read_secret($file) {
+        if (!file_exists($file)) {
+          throw new \RuntimeException(sprintf(
+            "Cannot start Nextcloud, secret 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
+          ));
+        }
+        return trim(file_get_contents($file));
+      }''}
+    function nix_decode_json_file($file, $error) {
+      if (!file_exists($file)) {
+        throw new \RuntimeException(sprintf($error, $file));
+      }
+      $decoded = json_decode(file_get_contents($file), true);
 
+      if (json_last_error() !== JSON_ERROR_NONE) {
+        throw new \RuntimeException(sprintf("Cannot decode %s, because: %s", $file, json_last_error_msg()));
+      }
+
+      return $decoded;
+    }
+    $CONFIG = [
+      'apps_paths' => [
+        ${concatStrings (mapAttrsToList mkAppStoreConfig appStores)}
+      ],
+      ${optionalString (showAppStoreSetting) "'appstoreenabled' => ${renderedAppStoreSetting},"}
+      ${optionalString cfg.caching.apcu "'memcache.local' => '\\OC\\Memcache\\APCu',"}
+      ${optionalString (c.dbname != null) "'dbname' => '${c.dbname}',"}
+      ${optionalString (c.dbhost != null) "'dbhost' => '${c.dbhost}',"}
+      ${optionalString (c.dbuser != null) "'dbuser' => '${c.dbuser}',"}
+      ${optionalString (c.dbtableprefix != null) "'dbtableprefix' => '${toString c.dbtableprefix}',"}
+      ${optionalString (c.dbpassFile != null) ''
+          'dbpassword' => nix_read_secret(
+            "${c.dbpassFile}"
+          ),
+        ''
+      }
+      'dbtype' => '${c.dbtype}',
+      ${objectstoreConfig}
+    ];
+
+    $CONFIG = array_replace_recursive($CONFIG, nix_decode_json_file(
+      "${jsonFormat.generate "nextcloud-settings.json" cfg.settings}",
+      "impossible: this should never happen (decoding generated settings file %s failed)"
+    ));
+
+    ${optionalString (cfg.secretFile != null) ''
+      $CONFIG = array_replace_recursive($CONFIG, nix_decode_json_file(
+        "${cfg.secretFile}",
+        "Cannot start Nextcloud, secrets file %s set by NixOS doesn't exist!"
+      ));
+    ''}
+  '';
 in {
 
   imports = [
@@ -115,21 +205,22 @@ in {
       Add port to services.nextcloud.config.dbhost instead.
     '')
     (mkRenamedOptionModule
-      [ "services" "nextcloud" "logLevel" ] [ "services" "nextcloud" "extraOptions" "loglevel" ])
+      [ "services" "nextcloud" "logLevel" ] [ "services" "nextcloud" "settings" "loglevel" ])
     (mkRenamedOptionModule
-      [ "services" "nextcloud" "logType" ] [ "services" "nextcloud" "extraOptions" "log_type" ])
+      [ "services" "nextcloud" "logType" ] [ "services" "nextcloud" "settings" "log_type" ])
     (mkRenamedOptionModule
-      [ "services" "nextcloud" "config" "defaultPhoneRegion" ] [ "services" "nextcloud" "extraOptions" "default_phone_region" ])
+      [ "services" "nextcloud" "config" "defaultPhoneRegion" ] [ "services" "nextcloud" "settings" "default_phone_region" ])
     (mkRenamedOptionModule
-      [ "services" "nextcloud" "config" "overwriteProtocol" ] [ "services" "nextcloud" "extraOptions" "overwriteprotocol" ])
+      [ "services" "nextcloud" "config" "overwriteProtocol" ] [ "services" "nextcloud" "settings" "overwriteprotocol" ])
     (mkRenamedOptionModule
-      [ "services" "nextcloud" "skeletonDirectory" ] [ "services" "nextcloud" "extraOptions" "skeletondirectory" ])
+      [ "services" "nextcloud" "skeletonDirectory" ] [ "services" "nextcloud" "settings" "skeletondirectory" ])
     (mkRenamedOptionModule
-      [ "services" "nextcloud" "globalProfiles" ] [ "services" "nextcloud" "extraOptions" "profile.enabled" ])
+      [ "services" "nextcloud" "globalProfiles" ] [ "services" "nextcloud" "settings" "profile.enabled" ])
     (mkRenamedOptionModule
-      [ "services" "nextcloud" "config" "extraTrustedDomains" ] [ "services" "nextcloud" "extraOptions" "trusted_domains" ])
+      [ "services" "nextcloud" "config" "extraTrustedDomains" ] [ "services" "nextcloud" "settings" "trusted_domains" ])
     (mkRenamedOptionModule
-      [ "services" "nextcloud" "config" "trustedProxies" ] [ "services" "nextcloud" "extraOptions" "trusted_proxies" ])
+      [ "services" "nextcloud" "config" "trustedProxies" ] [ "services" "nextcloud" "settings" "trusted_proxies" ])
+    (mkRenamedOptionModule ["services" "nextcloud" "extraOptions" ] [ "services" "nextcloud" "settings" ])
   ];
 
   options.services.nextcloud = {
@@ -558,7 +649,7 @@ in {
       '';
     };
 
-    extraOptions = mkOption {
+    settings = mkOption {
       type = types.submodule {
         freeformType = jsonFormat.type;
         options = {
@@ -680,7 +771,7 @@ in {
       default = null;
       description = lib.mdDoc ''
         Secret options which will be appended to Nextcloud's config.php file (written as JSON, in the same
-        form as the [](#opt-services.nextcloud.extraOptions) option), for example
+        form as the [](#opt-services.nextcloud.settings) option), for example
         `{"redis":{"password":"secret"}}`.
       '';
     };
@@ -782,112 +873,30 @@ in {
     { systemd.timers.nextcloud-cron = {
         wantedBy = [ "timers.target" ];
         after = [ "nextcloud-setup.service" ];
-        timerConfig.OnBootSec = "5m";
-        timerConfig.OnUnitActiveSec = "5m";
-        timerConfig.Unit = "nextcloud-cron.service";
+        timerConfig = {
+          OnBootSec = "5m";
+          OnUnitActiveSec = "5m";
+          Unit = "nextcloud-cron.service";
+        };
       };
 
-      systemd.tmpfiles.rules = ["d ${cfg.home} 0750 nextcloud nextcloud"];
+      systemd.tmpfiles.rules = map (dir: "d ${dir} 0750 nextcloud nextcloud - -") [
+        "${cfg.home}"
+        "${datadir}/config"
+        "${datadir}/data"
+        "${cfg.home}/store-apps"
+      ] ++ [
+        "L+ ${datadir}/config/override.config.php - - - - ${overrideConfig}"
+      ];
 
       systemd.services = {
         # When upgrading the Nextcloud package, Nextcloud can report errors such as
         # "The files of the app [all apps in /var/lib/nextcloud/apps] were not replaced correctly"
         # Restarting phpfpm on Nextcloud package update fixes these issues (but this is a workaround).
-        phpfpm-nextcloud.restartTriggers = [ webroot ];
+        phpfpm-nextcloud.restartTriggers = [ webroot overrideConfig ];
 
         nextcloud-setup = let
           c = cfg.config;
-          requiresReadSecretFunction = c.dbpassFile != null || c.objectstore.s3.enable;
-          objectstoreConfig = let s3 = c.objectstore.s3; in optionalString s3.enable ''
-            'objectstore' => [
-              'class' => '\\OC\\Files\\ObjectStore\\S3',
-              'arguments' => [
-                'bucket' => '${s3.bucket}',
-                'autocreate' => ${boolToString s3.autocreate},
-                'key' => '${s3.key}',
-                'secret' => nix_read_secret('${s3.secretFile}'),
-                ${optionalString (s3.hostname != null) "'hostname' => '${s3.hostname}',"}
-                ${optionalString (s3.port != null) "'port' => ${toString s3.port},"}
-                'use_ssl' => ${boolToString s3.useSsl},
-                ${optionalString (s3.region != null) "'region' => '${s3.region}',"}
-                'use_path_style' => ${boolToString s3.usePathStyle},
-                ${optionalString (s3.sseCKeyFile != null) "'sse_c_key' => nix_read_secret('${s3.sseCKeyFile}'),"}
-              ],
-            ]
-          '';
-
-          showAppStoreSetting = cfg.appstoreEnable != null || cfg.extraApps != {};
-          renderedAppStoreSetting =
-            let
-              x = cfg.appstoreEnable;
-            in
-              if x == null then "false"
-              else boolToString x;
-
-          nextcloudGreaterOrEqualThan = req: versionAtLeast cfg.package.version req;
-
-          mkAppStoreConfig = name: { enabled, writable, ... }: optionalString enabled ''
-            [ 'path' => '${webroot}/${name}', 'url' => '/${name}', 'writable' => ${boolToString writable} ],
-          '';
-
-          overrideConfig = pkgs.writeText "nextcloud-config.php" ''
-            <?php
-            ${optionalString requiresReadSecretFunction ''
-              function nix_read_secret($file) {
-                if (!file_exists($file)) {
-                  throw new \RuntimeException(sprintf(
-                    "Cannot start Nextcloud, secret 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
-                  ));
-                }
-                return trim(file_get_contents($file));
-              }''}
-            function nix_decode_json_file($file, $error) {
-              if (!file_exists($file)) {
-                throw new \RuntimeException(sprintf($error, $file));
-              }
-              $decoded = json_decode(file_get_contents($file), true);
-
-              if (json_last_error() !== JSON_ERROR_NONE) {
-                throw new \RuntimeException(sprintf("Cannot decode %s, because: %s", $file, json_last_error_msg()));
-              }
-
-              return $decoded;
-            }
-            $CONFIG = [
-              'apps_paths' => [
-                ${concatStrings (mapAttrsToList mkAppStoreConfig appStores)}
-              ],
-              ${optionalString (showAppStoreSetting) "'appstoreenabled' => ${renderedAppStoreSetting},"}
-              ${optionalString cfg.caching.apcu "'memcache.local' => '\\OC\\Memcache\\APCu',"}
-              ${optionalString (c.dbname != null) "'dbname' => '${c.dbname}',"}
-              ${optionalString (c.dbhost != null) "'dbhost' => '${c.dbhost}',"}
-              ${optionalString (c.dbuser != null) "'dbuser' => '${c.dbuser}',"}
-              ${optionalString (c.dbtableprefix != null) "'dbtableprefix' => '${toString c.dbtableprefix}',"}
-              ${optionalString (c.dbpassFile != null) ''
-                  'dbpassword' => nix_read_secret(
-                    "${c.dbpassFile}"
-                  ),
-                ''
-              }
-              'dbtype' => '${c.dbtype}',
-              ${objectstoreConfig}
-            ];
-
-            $CONFIG = array_replace_recursive($CONFIG, nix_decode_json_file(
-              "${jsonFormat.generate "nextcloud-extraOptions.json" cfg.extraOptions}",
-              "impossible: this should never happen (decoding generated extraOptions file %s failed)"
-            ));
-
-            ${optionalString (cfg.secretFile != null) ''
-              $CONFIG = array_replace_recursive($CONFIG, nix_decode_json_file(
-                "${cfg.secretFile}",
-                "Cannot start Nextcloud, secrets file %s set by NixOS doesn't exist!"
-              ));
-            ''}
-          '';
           occInstallCmd = let
             mkExport = { arg, value }: "export ${arg}=${value}";
             dbpass = {
@@ -924,7 +933,7 @@ in {
             (i: v: ''
               ${occ}/bin/nextcloud-occ config:system:set trusted_domains \
                 ${toString i} --value="${toString v}"
-            '') ([ cfg.hostName ] ++ cfg.extraOptions.trusted_domains));
+            '') ([ cfg.hostName ] ++ cfg.settings.trusted_domains));
 
         in {
           wantedBy = [ "multi-user.target" ];
@@ -932,6 +941,7 @@ in {
           after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
           requires = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
           path = [ occ ];
+          restartTriggers = [ overrideConfig ];
           script = ''
             ${optionalString (c.dbpassFile != null) ''
               if [ ! -r "${c.dbpassFile}" ]; then
@@ -959,18 +969,6 @@ in {
               fi
             '') [ "nix-apps" "apps" ]}
 
-            # create nextcloud directories.
-            # if the directories exist already with wrong permissions, we fix that
-            for dir in ${datadir}/config ${datadir}/data ${cfg.home}/store-apps; do
-              if [ ! -e $dir ]; then
-                install -o nextcloud -g nextcloud -d $dir
-              elif [ $(stat -c "%G" $dir) != "nextcloud" ]; then
-                chgrp -R nextcloud $dir
-              fi
-            done
-
-            ln -sf ${overrideConfig} ${datadir}/config/override.config.php
-
             # Do not install if already installed
             if [[ ! -e ${datadir}/config/config.php ]]; then
               ${occInstallCmd}
@@ -996,15 +994,21 @@ in {
         nextcloud-cron = {
           after = [ "nextcloud-setup.service" ];
           environment.NEXTCLOUD_CONFIG_DIR = "${datadir}/config";
-          serviceConfig.Type = "oneshot";
-          serviceConfig.User = "nextcloud";
-          serviceConfig.ExecStart = "${phpPackage}/bin/php -f ${webroot}/cron.php";
+          serviceConfig = {
+            Type = "oneshot";
+            User = "nextcloud";
+            ExecCondition = "${lib.getExe phpPackage} -f ${webroot}/occ status -e";
+            ExecStart = "${lib.getExe phpPackage} -f ${webroot}/cron.php";
+            KillMode = "process";
+          };
         };
         nextcloud-update-plugins = mkIf cfg.autoUpdateApps.enable {
           after = [ "nextcloud-setup.service" ];
-          serviceConfig.Type = "oneshot";
-          serviceConfig.ExecStart = "${occ}/bin/nextcloud-occ app:update --all";
-          serviceConfig.User = "nextcloud";
+          serviceConfig = {
+            Type = "oneshot";
+            ExecStart = "${occ}/bin/nextcloud-occ app:update --all";
+            User = "nextcloud";
+          };
           startAt = cfg.autoUpdateApps.startAt;
         };
       };
@@ -1061,7 +1065,7 @@ in {
 
       services.nextcloud = {
         caching.redis = lib.mkIf cfg.configureRedis true;
-        extraOptions = mkMerge [({
+        settings = mkMerge [({
           datadirectory = lib.mkDefault "${datadir}/data";
           trusted_domains = [ cfg.hostName ];
         }) (lib.mkIf cfg.configureRedis {
diff --git a/nixpkgs/nixos/modules/services/web-apps/nifi.nix b/nixpkgs/nixos/modules/services/web-apps/nifi.nix
index 5ce561077836..c0fc443f0df7 100644
--- a/nixpkgs/nixos/modules/services/web-apps/nifi.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/nifi.nix
@@ -163,10 +163,15 @@ in {
       Please do not disable HTTPS mode in production. In this mode, access to the nifi is opened without authentication.
     '';
 
-    systemd.tmpfiles.rules = [
-      "d '/var/lib/nifi/conf' 0750 ${cfg.user} ${cfg.group}"
-      "L+ '/var/lib/nifi/lib' - - - - ${cfg.package}/lib"
-    ];
+    systemd.tmpfiles.settings."10-nifi" = {
+      "/var/lib/nifi/conf".d = {
+        inherit (cfg) user group;
+        mode = "0750";
+      };
+      "/var/lib/nifi/lib"."L+" = {
+        argument = "${cfg.package}/lib";
+      };
+    };
 
 
     systemd.services.nifi = {
diff --git a/nixpkgs/nixos/modules/services/web-apps/openvscode-server.nix b/nixpkgs/nixos/modules/services/web-apps/openvscode-server.nix
index 76a19dccae16..81b9d1f3b4c8 100644
--- a/nixpkgs/nixos/modules/services/web-apps/openvscode-server.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/openvscode-server.nix
@@ -159,6 +159,7 @@ in
     systemd.services.openvscode-server = {
       description = "OpenVSCode server";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       path = cfg.extraPackages;
       environment = cfg.extraEnvironment;
diff --git a/nixpkgs/nixos/modules/services/web-apps/peering-manager.nix b/nixpkgs/nixos/modules/services/web-apps/peering-manager.nix
index d6f6077268d4..0382ce717473 100644
--- a/nixpkgs/nixos/modules/services/web-apps/peering-manager.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/peering-manager.nix
@@ -196,6 +196,7 @@ in {
     systemd.targets.peering-manager = {
       description = "Target for all Peering Manager services";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" "redis-peering-manager.service" ];
     };
 
diff --git a/nixpkgs/nixos/modules/services/web-apps/photoprism.nix b/nixpkgs/nixos/modules/services/web-apps/photoprism.nix
index e25b03484424..d3773cc9cf78 100644
--- a/nixpkgs/nixos/modules/services/web-apps/photoprism.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/photoprism.nix
@@ -18,7 +18,10 @@ let
     in
     pkgs.writeShellScript "manage" ''
       ${setupEnv}
-      exec ${cfg.package}/bin/photoprism "$@"
+      eval "$(${config.systemd.package}/bin/systemctl show -pUID,MainPID photoprism.service | ${pkgs.gnused}/bin/sed "s/UID/ServiceUID/")"
+      exec ${pkgs.util-linux}/bin/nsenter \
+        -t $MainPID -m -S $ServiceUID -G $ServiceUID --wdns=${cfg.storagePath} \
+        ${cfg.package}/bin/photoprism "$@"
     '';
 in
 {
diff --git a/nixpkgs/nixos/modules/services/web-apps/pretalx.nix b/nixpkgs/nixos/modules/services/web-apps/pretalx.nix
new file mode 100644
index 000000000000..ff6218112d2f
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/pretalx.nix
@@ -0,0 +1,415 @@
+{ config
+, lib
+, pkgs
+, utils
+, ...
+}:
+
+let
+  cfg = config.services.pretalx;
+  format = pkgs.formats.ini { };
+
+  configFile = format.generate "pretalx.cfg" cfg.settings;
+
+  extras = cfg.package.optional-dependencies.redis
+    ++ lib.optionals (cfg.settings.database.backend == "mysql") cfg.package.optional-dependencies.mysql
+    ++ lib.optionals (cfg.settings.database.backend == "postgresql") cfg.package.optional-dependencies.postgres;
+
+  pythonEnv = cfg.package.python.buildEnv.override {
+    extraLibs = [ (cfg.package.python.pkgs.toPythonModule cfg.package) ]
+      ++ (with cfg.package.python.pkgs; [ gunicorn ]
+      ++ lib.optional cfg.celery.enable celery) ++ extras;
+  };
+in
+
+{
+  meta = with lib; {
+    maintainers = teams.c3d2.members;
+  };
+
+  options.services.pretalx = {
+    enable = lib.mkEnableOption (lib.mdDoc "pretalx");
+
+    package = lib.mkPackageOptionMD pkgs "pretalx" {};
+
+    group = lib.mkOption {
+      type = lib.types.str;
+      default = "pretalx";
+      description = "Group under which pretalx should run.";
+    };
+
+    user = lib.mkOption {
+      type = lib.types.str;
+      default = "pretalx";
+      description = "User under which pretalx should run.";
+    };
+
+    gunicorn.extraArgs = lib.mkOption {
+      type = with lib.types; listOf str;
+      default = [
+        "--name=pretalx"
+      ];
+      example = [
+        "--name=pretalx"
+        "--workers=4"
+        "--max-requests=1200"
+        "--max-requests-jitter=50"
+        "--log-level=info"
+      ];
+      description = lib.mdDoc ''
+        Extra arguments to pass to gunicorn.
+        See <https://docs.pretalx.org/administrator/installation.html#step-6-starting-pretalx-as-a-service> for details.
+      '';
+      apply = lib.escapeShellArgs;
+    };
+
+    celery = {
+      enable = lib.mkOption {
+        type = lib.types.bool;
+        default = true;
+        example = false;
+        description = lib.mdDoc ''
+          Whether to set up celery as an asynchronous task runner.
+        '';
+      };
+
+      extraArgs = lib.mkOption {
+        type = with lib.types; listOf str;
+        default = [ ];
+        description = lib.mdDoc ''
+          Extra arguments to pass to celery.
+
+          See <https://docs.celeryq.dev/en/stable/reference/cli.html#celery-worker> for more info.
+        '';
+        apply = utils.escapeSystemdExecArgs;
+      };
+    };
+
+    nginx = {
+      enable = lib.mkOption {
+        type = lib.types.bool;
+        default = true;
+        example = false;
+        description = lib.mdDoc ''
+          Whether to set up an nginx virtual host.
+        '';
+      };
+
+      domain = lib.mkOption {
+        type = lib.types.str;
+        example = "talks.example.com";
+        description = lib.mdDoc ''
+          The domain name under which to set up the virtual host.
+        '';
+      };
+    };
+
+    database.createLocally = lib.mkOption {
+      type = lib.types.bool;
+      default = true;
+      example = false;
+      description = lib.mdDoc ''
+        Whether to automatically set up the database on the local DBMS instance.
+
+        Currently only supported for PostgreSQL. Not required for sqlite.
+      '';
+    };
+
+    settings = lib.mkOption {
+      type = lib.types.submodule {
+        freeformType = format.type;
+        options = {
+          database = {
+            backend = lib.mkOption {
+              type = lib.types.enum [
+                "postgresql"
+              ];
+              default = "postgresql";
+              description = lib.mdDoc ''
+                Database backend to use.
+
+                Currently only PostgreSQL gets tested, and as such we don't support any other DBMS.
+              '';
+              readOnly = true; # only postgres supported right now
+            };
+
+            host = lib.mkOption {
+              type = with lib.types; nullOr types.path;
+              default = if cfg.settings.database.backend == "postgresql" then "/run/postgresql"
+                else if cfg.settings.database.backend == "mysql" then "/run/mysqld/mysqld.sock"
+                else null;
+              defaultText = lib.literalExpression ''
+                if config.services.pretalx.settings..database.backend == "postgresql" then "/run/postgresql"
+                else if config.services.pretalx.settings.database.backend == "mysql" then "/run/mysqld/mysqld.sock"
+                else null
+              '';
+              description = lib.mdDoc ''
+                Database host or socket path.
+              '';
+            };
+
+            name = lib.mkOption {
+              type = lib.types.str;
+              default = "pretalx";
+              description = lib.mdDoc ''
+                Database name.
+              '';
+            };
+
+            user = lib.mkOption {
+              type = lib.types.str;
+              default = "pretalx";
+              description = lib.mdDoc ''
+                Database username.
+              '';
+            };
+          };
+
+          filesystem = {
+            data = lib.mkOption {
+              type = lib.types.path;
+              default = "/var/lib/pretalx";
+              description = lib.mdDoc ''
+                Base path for all other storage paths.
+              '';
+            };
+            logs = lib.mkOption {
+              type = lib.types.path;
+              default = "/var/log/pretalx";
+              description = lib.mdDoc ''
+                Path to the log directory, that pretalx logs message to.
+              '';
+            };
+            static = lib.mkOption {
+              type = lib.types.path;
+              default = "${cfg.package.static}/";
+              defaultText = lib.literalExpression "\${config.services.pretalx.package}.static}/";
+              readOnly = true;
+              description = lib.mdDoc ''
+                Path to the directory that contains static files.
+              '';
+            };
+          };
+
+          celery = {
+            backend = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = lib.optionalString cfg.celery.enable "redis+socket://${config.services.redis.servers.pretalx.unixSocket}?virtual_host=1";
+              defaultText = lib.literalExpression ''
+                optionalString config.services.pretalx.celery.enable "redis+socket://''${config.services.redis.servers.pretalx.unixSocket}?virtual_host=1"
+              '';
+              description = lib.mdDoc ''
+                URI to the celery backend used for the asynchronous job queue.
+              '';
+            };
+
+            broker = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = lib.optionalString cfg.celery.enable "redis+socket://${config.services.redis.servers.pretalx.unixSocket}?virtual_host=2";
+              defaultText = lib.literalExpression ''
+                optionalString config.services.pretalx.celery.enable "redis+socket://''${config.services.redis.servers.pretalx.unixSocket}?virtual_host=2"
+              '';
+              description = lib.mdDoc ''
+                URI to the celery broker used for the asynchronous job queue.
+              '';
+            };
+          };
+
+          redis = {
+            location = lib.mkOption {
+              type = with lib.types; nullOr str;
+              default = "unix://${config.services.redis.servers.pretalx.unixSocket}?db=0";
+              defaultText = lib.literalExpression ''
+                "unix://''${config.services.redis.servers.pretalx.unixSocket}?db=0"
+              '';
+              description = lib.mdDoc ''
+                URI to the redis server, used to speed up locking, caching and session storage.
+              '';
+            };
+
+            session = lib.mkOption {
+              type = lib.types.bool;
+              default = true;
+              example = false;
+              description = lib.mdDoc ''
+                Whether to use redis as the session storage.
+              '';
+            };
+          };
+
+          site = {
+            url = lib.mkOption {
+              type = lib.types.str;
+              default = "https://${cfg.nginx.domain}";
+              defaultText = lib.literalExpression "https://\${config.services.pretalx.nginx.domain}";
+              example = "https://talks.example.com";
+              description = lib.mdDoc ''
+                The base URI below which your pretalx instance will be reachable.
+              '';
+            };
+          };
+        };
+      };
+      default = { };
+      description = lib.mdDoc ''
+        pretalx configuration as a Nix attribute set. All settings can also be passed
+        from the environment.
+
+        See <https://docs.pretalx.org/administrator/configure.html> for possible options.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    # https://docs.pretalx.org/administrator/installation.html
+
+    environment.systemPackages = [
+      (pkgs.writeScriptBin "pretalx-manage" ''
+        cd ${cfg.settings.filesystem.data}
+        sudo=exec
+        if [[ "$USER" != ${cfg.user} ]]; then
+          sudo='exec /run/wrappers/bin/sudo -u ${cfg.user} --preserve-env=PRETALX_CONFIG_FILE'
+        fi
+        export PRETALX_CONFIG_FILE=${configFile}
+        $sudo ${lib.getExe' pythonEnv "pretalx-manage"} "$@"
+      '')
+    ];
+
+    services = {
+      nginx = lib.mkIf cfg.nginx.enable {
+        enable = true;
+        recommendedGzipSettings = lib.mkDefault true;
+        recommendedOptimisation = lib.mkDefault true;
+        recommendedProxySettings = lib.mkDefault true;
+        recommendedTlsSettings = lib.mkDefault true;
+        upstreams.pretalx.servers."unix:/run/pretalx/pretalx.sock" = { };
+        virtualHosts.${cfg.nginx.domain} = {
+          # https://docs.pretalx.org/administrator/installation.html#step-7-ssl
+          extraConfig = ''
+            more_set_headers Referrer-Policy same-origin;
+            more_set_headers X-Content-Type-Options nosniff;
+          '';
+          locations = {
+            "/".proxyPass = "http://pretalx";
+            "/media/" = {
+              alias = "${cfg.settings.filesystem.data}/data/media/";
+              extraConfig = ''
+                access_log off;
+                more_set_headers Content-Disposition 'attachment; filename="$1"';
+                expires 7d;
+              '';
+            };
+            "/static/" = {
+              alias = cfg.settings.filesystem.static;
+              extraConfig = ''
+                access_log off;
+                more_set_headers Cache-Control "public";
+                expires 365d;
+              '';
+            };
+          };
+        };
+      };
+
+      postgresql = lib.mkIf (cfg.database.createLocally && cfg.settings.database.backend == "postgresql") {
+        enable = true;
+        ensureUsers = [ {
+          name = cfg.settings.database.user;
+          ensureDBOwnership = true;
+        } ];
+        ensureDatabases = [ cfg.settings.database.name ];
+      };
+
+      redis.servers.pretalx.enable = true;
+    };
+
+    systemd.services = let
+      commonUnitConfig = {
+        environment.PRETALX_CONFIG_FILE = configFile;
+        serviceConfig = {
+          User = "pretalx";
+          Group = "pretalx";
+          StateDirectory = [ "pretalx" "pretalx/media" ];
+          LogsDirectory = "pretalx";
+          WorkingDirectory = cfg.settings.filesystem.data;
+          SupplementaryGroups = [ "redis-pretalx" ];
+        };
+      };
+    in {
+      pretalx-web = lib.recursiveUpdate commonUnitConfig {
+        description = "pretalx web service";
+        after = [
+          "network.target"
+          "redis-pretalx.service"
+        ] ++ lib.optionals (cfg.settings.database.backend == "postgresql") [
+          "postgresql.service"
+        ] ++ lib.optionals (cfg.settings.database.backend == "mysql") [
+          "mysql.service"
+        ];
+        wantedBy = [ "multi-user.target" ];
+        preStart = ''
+          versionFile="${cfg.settings.filesystem.data}/.version"
+          version=$(cat "$versionFile" 2>/dev/null || echo 0)
+
+          if [[ $version != ${cfg.package.version} ]]; then
+            ${lib.getExe' pythonEnv "pretalx-manage"} migrate
+
+            echo "${cfg.package.version}" > "$versionFile"
+          fi
+        '';
+        serviceConfig = {
+          ExecStart = "${lib.getExe' pythonEnv "gunicorn"} --bind unix:/run/pretalx/pretalx.sock ${cfg.gunicorn.extraArgs} pretalx.wsgi";
+          RuntimeDirectory = "pretalx";
+        };
+      };
+
+      pretalx-periodic = lib.recursiveUpdate commonUnitConfig {
+        description = "pretalx periodic task runner";
+        # every 15 minutes
+        startAt = [ "*:3,18,33,48" ];
+        serviceConfig = {
+          Type = "oneshot";
+          ExecStart = "${lib.getExe' pythonEnv "pretalx-manage"} runperiodic";
+        };
+      };
+
+      pretalx-clear-sessions = lib.recursiveUpdate commonUnitConfig {
+        description = "pretalx session pruning";
+        startAt = [ "monthly" ];
+        serviceConfig = {
+          Type = "oneshot";
+          ExecStart = "${lib.getExe' pythonEnv "pretalx-manage"} clearsessions";
+        };
+      };
+
+      pretalx-worker = lib.mkIf cfg.celery.enable (lib.recursiveUpdate commonUnitConfig {
+        description = "pretalx asynchronous job runner";
+        after = [
+          "network.target"
+          "redis-pretalx.service"
+        ] ++ lib.optionals (cfg.settings.database.backend == "postgresql") [
+          "postgresql.service"
+        ] ++ lib.optionals (cfg.settings.database.backend == "mysql") [
+          "mysql.service"
+        ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig.ExecStart = "${lib.getExe' pythonEnv "celery"} -A pretalx.celery_app worker ${cfg.celery.extraArgs}";
+      });
+    };
+
+    systemd.sockets.pretalx-web.socketConfig = {
+      ListenStream = "/run/pretalx/pretalx.sock";
+      SocketUser = "nginx";
+    };
+
+    users = {
+      groups."${cfg.group}" = {};
+      users."${cfg.user}" = {
+        isSystemUser = true;
+        createHome = true;
+        home = cfg.settings.filesystem.data;
+        inherit (cfg) group;
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/web-apps/restya-board.nix b/nixpkgs/nixos/modules/services/web-apps/restya-board.nix
deleted file mode 100644
index 959bcbc5c9f1..000000000000
--- a/nixpkgs/nixos/modules/services/web-apps/restya-board.nix
+++ /dev/null
@@ -1,380 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-# TODO: are these php-packages needed?
-#imagick
-#php-geoip -> php.ini: extension = geoip.so
-#expat
-
-let
-  cfg = config.services.restya-board;
-  fpm = config.services.phpfpm.pools.${poolName};
-
-  runDir = "/run/restya-board";
-
-  poolName = "restya-board";
-
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    services.restya-board = {
-
-      enable = mkEnableOption (lib.mdDoc "restya-board");
-
-      dataDir = mkOption {
-        type = types.path;
-        default = "/var/lib/restya-board";
-        description = lib.mdDoc ''
-          Data of the application.
-        '';
-      };
-
-      user = mkOption {
-        type = types.str;
-        default = "restya-board";
-        description = lib.mdDoc ''
-          User account under which the web-application runs.
-        '';
-      };
-
-      group = mkOption {
-        type = types.str;
-        default = "nginx";
-        description = lib.mdDoc ''
-          Group account under which the web-application runs.
-        '';
-      };
-
-      virtualHost = {
-        serverName = mkOption {
-          type = types.str;
-          default = "restya.board";
-          description = lib.mdDoc ''
-            Name of the nginx virtualhost to use.
-          '';
-        };
-
-        listenHost = mkOption {
-          type = types.str;
-          default = "localhost";
-          description = lib.mdDoc ''
-            Listen address for the virtualhost to use.
-          '';
-        };
-
-        listenPort = mkOption {
-          type = types.port;
-          default = 3000;
-          description = lib.mdDoc ''
-            Listen port for the virtualhost to use.
-          '';
-        };
-      };
-
-      database = {
-        host = mkOption {
-          type = types.nullOr types.str;
-          default = null;
-          description = lib.mdDoc ''
-            Host of the database. Leave 'null' to use a local PostgreSQL database.
-            A local PostgreSQL database is initialized automatically.
-          '';
-        };
-
-        port = mkOption {
-          type = types.nullOr types.int;
-          default = 5432;
-          description = lib.mdDoc ''
-            The database's port.
-          '';
-        };
-
-        name = mkOption {
-          type = types.str;
-          default = "restya_board";
-          description = lib.mdDoc ''
-            Name of the database. The database must exist.
-          '';
-        };
-
-        user = mkOption {
-          type = types.str;
-          default = "restya_board";
-          description = lib.mdDoc ''
-            The database user. The user must exist and have access to
-            the specified database.
-          '';
-        };
-
-        passwordFile = mkOption {
-          type = types.nullOr types.path;
-          default = null;
-          description = lib.mdDoc ''
-            The database user's password. 'null' if no password is set.
-          '';
-        };
-      };
-
-      email = {
-        server = mkOption {
-          type = types.nullOr types.str;
-          default = null;
-          example = "localhost";
-          description = lib.mdDoc ''
-            Hostname to send outgoing mail. Null to use the system MTA.
-          '';
-        };
-
-        port = mkOption {
-          type = types.port;
-          default = 25;
-          description = lib.mdDoc ''
-            Port used to connect to SMTP server.
-          '';
-        };
-
-        login = mkOption {
-          type = types.str;
-          default = "";
-          description = lib.mdDoc ''
-            SMTP authentication login used when sending outgoing mail.
-          '';
-        };
-
-        password = mkOption {
-          type = types.str;
-          default = "";
-          description = lib.mdDoc ''
-            SMTP authentication password used when sending outgoing mail.
-
-            ATTENTION: The password is stored world-readable in the nix-store!
-          '';
-        };
-      };
-
-      timezone = mkOption {
-        type = types.lines;
-        default = "GMT";
-        description = lib.mdDoc ''
-          Timezone the web-app runs in.
-        '';
-      };
-
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-
-    services.phpfpm.pools = {
-      ${poolName} = {
-        inherit (cfg) user group;
-
-        phpOptions = ''
-          date.timezone = "CET"
-
-          ${optionalString (cfg.email.server != null) ''
-            SMTP = ${cfg.email.server}
-            smtp_port = ${toString cfg.email.port}
-            auth_username = ${cfg.email.login}
-            auth_password = ${cfg.email.password}
-          ''}
-        '';
-        settings = mapAttrs (name: mkDefault) {
-          "listen.owner" = "nginx";
-          "listen.group" = "nginx";
-          "listen.mode" = "0600";
-          "pm" = "dynamic";
-          "pm.max_children" = 75;
-          "pm.start_servers" = 10;
-          "pm.min_spare_servers" = 5;
-          "pm.max_spare_servers" = 20;
-          "pm.max_requests" = 500;
-          "catch_workers_output" = 1;
-        };
-      };
-    };
-
-    services.nginx.enable = true;
-    services.nginx.virtualHosts.${cfg.virtualHost.serverName} = {
-      listen = [ { addr = cfg.virtualHost.listenHost; port = cfg.virtualHost.listenPort; } ];
-      serverName = cfg.virtualHost.serverName;
-      root = runDir;
-      extraConfig = ''
-        index index.html index.php;
-
-        gzip on;
-
-        gzip_comp_level 6;
-        gzip_min_length  1100;
-        gzip_buffers 16 8k;
-        gzip_proxied any;
-        gzip_types text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/json application/xml+rss;
-
-        client_max_body_size 300M;
-
-        rewrite ^/oauth/authorize$ /server/php/authorize.php last;
-        rewrite ^/oauth_callback/([a-zA-Z0-9_\.]*)/([a-zA-Z0-9_\.]*)$ /server/php/oauth_callback.php?plugin=$1&code=$2 last;
-        rewrite ^/download/([0-9]*)/([a-zA-Z0-9_\.]*)$ /server/php/download.php?id=$1&hash=$2 last;
-        rewrite ^/ical/([0-9]*)/([0-9]*)/([a-z0-9]*).ics$ /server/php/ical.php?board_id=$1&user_id=$2&hash=$3 last;
-        rewrite ^/api/(.*)$ /server/php/R/r.php?_url=$1&$args last;
-        rewrite ^/api_explorer/api-docs/$ /client/api_explorer/api-docs/index.php last;
-      '';
-
-      locations."/".root = "${runDir}/client";
-
-      locations."~ \\.php$" = {
-        tryFiles = "$uri =404";
-        extraConfig = ''
-          include ${config.services.nginx.package}/conf/fastcgi_params;
-          fastcgi_pass    unix:${fpm.socket};
-          fastcgi_index   index.php;
-          fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
-          fastcgi_param   PHP_VALUE "upload_max_filesize=9G \n post_max_size=9G \n max_execution_time=200 \n max_input_time=200 \n memory_limit=256M";
-        '';
-      };
-
-      locations."~* \\.(css|js|less|html|ttf|woff|jpg|jpeg|gif|png|bmp|ico)" = {
-        root = "${runDir}/client";
-        extraConfig = ''
-          if (-f $request_filename) {
-                  break;
-          }
-          rewrite ^/img/([a-zA-Z_]*)/([a-zA-Z_]*)/([a-zA-Z0-9_\.]*)$ /server/php/image.php?size=$1&model=$2&filename=$3 last;
-          add_header        Cache-Control public;
-          add_header        Cache-Control must-revalidate;
-          expires           7d;
-        '';
-      };
-    };
-
-    systemd.services.restya-board-init = {
-      description = "Restya board initialization";
-      serviceConfig.Type = "oneshot";
-      serviceConfig.RemainAfterExit = true;
-
-      wantedBy = [ "multi-user.target" ];
-      requires = lib.optional (cfg.database.host != null) "postgresql.service";
-      after = [ "network.target" ] ++ (lib.optional (cfg.database.host != null) "postgresql.service");
-
-      script = ''
-        rm -rf "${runDir}"
-        mkdir -m 750 -p "${runDir}"
-        cp -r "${pkgs.restya-board}/"* "${runDir}"
-        sed -i "s/@restya.com/@${cfg.virtualHost.serverName}/g" "${runDir}/sql/restyaboard_with_empty_data.sql"
-        rm -rf "${runDir}/media"
-        rm -rf "${runDir}/client/img"
-        chmod -R 0750 "${runDir}"
-
-        sed -i "s@^php@${config.services.phpfpm.phpPackage}/bin/php@" "${runDir}/server/php/shell/"*.sh
-
-        ${if (cfg.database.host == null) then ''
-          sed -i "s/^.*'R_DB_HOST'.*$/define('R_DB_HOST', 'localhost');/g" "${runDir}/server/php/config.inc.php"
-          sed -i "s/^.*'R_DB_PASSWORD'.*$/define('R_DB_PASSWORD', 'restya');/g" "${runDir}/server/php/config.inc.php"
-        '' else ''
-          sed -i "s/^.*'R_DB_HOST'.*$/define('R_DB_HOST', '${cfg.database.host}');/g" "${runDir}/server/php/config.inc.php"
-          sed -i "s/^.*'R_DB_PASSWORD'.*$/define('R_DB_PASSWORD', ${if cfg.database.passwordFile == null then "''" else "'$(cat ${cfg.database.passwordFile})');/g"}" "${runDir}/server/php/config.inc.php"
-        ''}
-        sed -i "s/^.*'R_DB_PORT'.*$/define('R_DB_PORT', '${toString cfg.database.port}');/g" "${runDir}/server/php/config.inc.php"
-        sed -i "s/^.*'R_DB_NAME'.*$/define('R_DB_NAME', '${cfg.database.name}');/g" "${runDir}/server/php/config.inc.php"
-        sed -i "s/^.*'R_DB_USER'.*$/define('R_DB_USER', '${cfg.database.user}');/g" "${runDir}/server/php/config.inc.php"
-
-        chmod 0400 "${runDir}/server/php/config.inc.php"
-
-        ln -sf "${cfg.dataDir}/media" "${runDir}/media"
-        ln -sf "${cfg.dataDir}/client/img" "${runDir}/client/img"
-
-        chmod g+w "${runDir}/tmp/cache"
-        chown -R "${cfg.user}":"${cfg.group}" "${runDir}"
-
-
-        mkdir -m 0750 -p "${cfg.dataDir}"
-        mkdir -m 0750 -p "${cfg.dataDir}/media"
-        mkdir -m 0750 -p "${cfg.dataDir}/client/img"
-        cp -r "${pkgs.restya-board}/media/"* "${cfg.dataDir}/media"
-        cp -r "${pkgs.restya-board}/client/img/"* "${cfg.dataDir}/client/img"
-        chown "${cfg.user}":"${cfg.group}" "${cfg.dataDir}"
-        chown -R "${cfg.user}":"${cfg.group}" "${cfg.dataDir}/media"
-        chown -R "${cfg.user}":"${cfg.group}" "${cfg.dataDir}/client/img"
-
-        ${optionalString (cfg.database.host == null) ''
-          if ! [ -e "${cfg.dataDir}/.db-initialized" ]; then
-            ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} \
-              ${config.services.postgresql.package}/bin/psql -U ${config.services.postgresql.superUser} \
-              -c "CREATE USER ${cfg.database.user} WITH ENCRYPTED PASSWORD 'restya'"
-
-            ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} \
-              ${config.services.postgresql.package}/bin/psql -U ${config.services.postgresql.superUser} \
-              -c "CREATE DATABASE ${cfg.database.name} OWNER ${cfg.database.user} ENCODING 'UTF8' TEMPLATE template0"
-
-            ${pkgs.sudo}/bin/sudo -u ${cfg.user} \
-              ${config.services.postgresql.package}/bin/psql -U ${cfg.database.user} \
-              -d ${cfg.database.name} -f "${runDir}/sql/restyaboard_with_empty_data.sql"
-
-            touch "${cfg.dataDir}/.db-initialized"
-          fi
-        ''}
-      '';
-    };
-
-    systemd.timers.restya-board = {
-      description = "restya-board scripts for e.g. email notification";
-      wantedBy = [ "timers.target" ];
-      after = [ "restya-board-init.service" ];
-      requires = [ "restya-board-init.service" ];
-      timerConfig = {
-        OnUnitInactiveSec = "60s";
-        Unit = "restya-board-timers.service";
-      };
-    };
-
-    systemd.services.restya-board-timers = {
-      description = "restya-board scripts for e.g. email notification";
-      serviceConfig.Type = "oneshot";
-      serviceConfig.User = cfg.user;
-
-      after = [ "restya-board-init.service" ];
-      requires = [ "restya-board-init.service" ];
-
-      script = ''
-        /bin/sh ${runDir}/server/php/shell/instant_email_notification.sh 2> /dev/null || true
-        /bin/sh ${runDir}/server/php/shell/periodic_email_notification.sh 2> /dev/null || true
-        /bin/sh ${runDir}/server/php/shell/imap.sh 2> /dev/null || true
-        /bin/sh ${runDir}/server/php/shell/webhook.sh 2> /dev/null || true
-        /bin/sh ${runDir}/server/php/shell/card_due_notification.sh 2> /dev/null || true
-      '';
-    };
-
-    users.users.restya-board = {
-      isSystemUser = true;
-      createHome = false;
-      home = runDir;
-      group  = "restya-board";
-    };
-    users.groups.restya-board = {};
-
-    services.postgresql.enable = mkIf (cfg.database.host == null) true;
-
-    services.postgresql.identMap = optionalString (cfg.database.host == null)
-      ''
-        restya-board-users restya-board restya_board
-      '';
-
-    services.postgresql.authentication = optionalString (cfg.database.host == null)
-      ''
-        local restya_board all ident map=restya-board-users
-      '';
-
-  };
-
-}
-
diff --git a/nixpkgs/nixos/modules/services/web-apps/suwayomi-server.md b/nixpkgs/nixos/modules/services/web-apps/suwayomi-server.md
new file mode 100644
index 000000000000..ff1e06c8a53a
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/suwayomi-server.md
@@ -0,0 +1,108 @@
+# Suwayomi-Server {#module-services-suwayomi-server}
+
+A free and open source manga reader server that runs extensions built for Tachiyomi.
+
+## Basic usage {#module-services-suwayomi-server-basic-usage}
+
+By default, the module will execute Suwayomi-Server backend and web UI:
+
+```nix
+{ ... }:
+
+{
+  services.suwayomi-server = {
+    enable = true;
+  };
+}
+```
+
+It runs in the systemd service named `suwayomi-server` in the data directory `/var/lib/suwayomi-server`.
+
+You can change the default parameters with some other parameters:
+```nix
+{ ... }:
+
+{
+  services.suwayomi-server = {
+    enable = true;
+
+    dataDir = "/var/lib/suwayomi"; # Default is "/var/lib/suwayomi-server"
+    openFirewall = true;
+
+    settings = {
+      server.port = 4567;
+    };
+  };
+}
+```
+
+If you want to create a desktop icon, you can activate the system tray option:
+
+```nix
+{ ... }:
+
+{
+  services.suwayomi-server = {
+    enable = true;
+
+    dataDir = "/var/lib/suwayomi"; # Default is "/var/lib/suwayomi-server"
+    openFirewall = true;
+
+    settings = {
+      server.port = 4567;
+      server.enableSystemTray = true;
+    };
+  };
+}
+```
+
+## Basic authentication {#module-services-suwayomi-server-basic-auth}
+
+You can configure a basic authentication to the web interface with:
+
+```nix
+{ ... }:
+
+{
+  services.suwayomi-server = {
+    enable = true;
+
+    openFirewall = true;
+
+    settings = {
+      server.port = 4567;
+      server = {
+        basicAuthEnabled = true;
+        basicAuthUsername = "username";
+
+        # NOTE: this is not a real upstream option
+        basicAuthPasswordFile = ./path/to/the/password/file;
+      };
+    };
+  };
+}
+```
+
+## Extra configuration {#module-services-suwayomi-server-extra-config}
+
+Not all the configuration options are available directly in this module, but you can add the other options of suwayomi-server with:
+
+```nix
+{ ... }:
+
+{
+  services.suwayomi-server = {
+    enable = true;
+
+    openFirewall = true;
+
+    settings = {
+      server = {
+        port = 4567;
+        autoDownloadNewChapters = false;
+        maxSourcesInParallel" = 6;
+      };
+    };
+  };
+}
+```
diff --git a/nixpkgs/nixos/modules/services/web-apps/suwayomi-server.nix b/nixpkgs/nixos/modules/services/web-apps/suwayomi-server.nix
new file mode 100644
index 000000000000..94dbe6f99356
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/suwayomi-server.nix
@@ -0,0 +1,215 @@
+{ config, pkgs, lib, ... }:
+
+let
+  cfg = config.services.suwayomi-server;
+  inherit (lib) mkOption mdDoc mkEnableOption mkIf types;
+
+  format = pkgs.formats.hocon { };
+in
+{
+  options = {
+    services.suwayomi-server = {
+      enable = mkEnableOption (mdDoc "Suwayomi, a free and open source manga reader server that runs extensions built for Tachiyomi.");
+
+      package = lib.mkPackageOptionMD pkgs "suwayomi-server" { };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/lib/suwayomi-server";
+        example = "/var/data/mangas";
+        description = mdDoc ''
+          The path to the data directory in which Suwayomi-Server will download scans.
+        '';
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "suwayomi";
+        example = "root";
+        description = mdDoc ''
+          User account under which Suwayomi-Server runs.
+        '';
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "suwayomi";
+        example = "medias";
+        description = mdDoc ''
+          Group under which Suwayomi-Server runs.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = mdDoc ''
+          Whether to open the firewall for the port in {option}`services.suwayomi-server.settings.server.port`.
+        '';
+      };
+
+      settings = mkOption {
+        type = types.submodule {
+          freeformType = format.type;
+          options = {
+            server = {
+              ip = mkOption {
+                type = types.str;
+                default = "0.0.0.0";
+                example = "127.0.0.1";
+                description = mdDoc ''
+                  The ip that Suwayomi will bind to.
+                '';
+              };
+
+              port = mkOption {
+                type = types.port;
+                default = 8080;
+                example = 4567;
+                description = mdDoc ''
+                  The port that Suwayomi will listen to.
+                '';
+              };
+
+              basicAuthEnabled = mkEnableOption (mdDoc ''
+                Add basic access authentication to Suwayomi-Server.
+                Enabling this option is useful when hosting on a public network/the Internet
+              '');
+
+              basicAuthUsername = mkOption {
+                type = types.nullOr types.str;
+                default = null;
+                description = mdDoc ''
+                  The username value that you have to provide when authenticating.
+                '';
+              };
+
+              # NOTE: this is not a real upstream option
+              basicAuthPasswordFile = mkOption {
+                type = types.nullOr types.path;
+                default = null;
+                example = "/var/secrets/suwayomi-server-password";
+                description = mdDoc ''
+                  The password file containing the value that you have to provide when authenticating.
+                '';
+              };
+
+              downloadAsCbz = mkOption {
+                type = types.bool;
+                default = false;
+                description = mdDoc ''
+                  Download chapters as `.cbz` files.
+                '';
+              };
+
+              localSourcePath = mkOption {
+                type = types.path;
+                default = cfg.dataDir;
+                defaultText = lib.literalExpression "suwayomi-server.dataDir";
+                example = "/var/data/local_mangas";
+                description = mdDoc ''
+                  Path to the local source folder.
+                '';
+              };
+
+              systemTrayEnabled = mkOption {
+                type = types.bool;
+                default = false;
+                description = mdDoc ''
+                  Whether to enable a system tray icon, if possible.
+                '';
+              };
+            };
+          };
+        };
+        description = mdDoc ''
+          Configuration to write to {file}`server.conf`.
+          See <https://github.com/Suwayomi/Suwayomi-Server/wiki/Configuring-Suwayomi-Server> for more information.
+        '';
+        default = { };
+        example = {
+          server.socksProxyEnabled = true;
+          server.socksProxyHost = "yourproxyhost.com";
+          server.socksProxyPort = "8080";
+        };
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    assertions = [{
+      assertion = with cfg.settings.server; basicAuthEnabled -> (basicAuthUsername != null && basicAuthPasswordFile != null);
+      message = ''
+        [suwayomi-server]: the username and the password file cannot be null when the basic auth is enabled
+      '';
+    }];
+
+    networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.server.port ];
+
+    users.groups = mkIf (cfg.group == "suwayomi") {
+      suwayomi = { };
+    };
+
+    users.users = mkIf (cfg.user == "suwayomi") {
+      suwayomi = {
+        group = cfg.group;
+        # Need to set the user home because the package writes to ~/.local/Tachidesk
+        home = cfg.dataDir;
+        description = "Suwayomi Daemon user";
+        isSystemUser = true;
+      };
+    };
+
+    systemd.tmpfiles.settings."10-suwayomi-server" = {
+      "${cfg.dataDir}/.local/share/Tachidesk".d = {
+        mode = "0700";
+        inherit (cfg) user group;
+      };
+    };
+
+    systemd.services.suwayomi-server =
+      let
+        configFile = format.generate "server.conf" (lib.pipe cfg.settings [
+          (settings: lib.recursiveUpdate settings {
+            server.basicAuthPasswordFile = null;
+            server.basicAuthPassword =
+              if settings.server.basicAuthEnabled
+              then "$TACHIDESK_SERVER_BASIC_AUTH_PASSWORD"
+              else null;
+          })
+          (lib.filterAttrsRecursive (_: x: x != null))
+        ]);
+      in
+      {
+        description = "A free and open source manga reader server that runs extensions built for Tachiyomi.";
+
+        wantedBy = [ "multi-user.target" ];
+        wants = [ "network-online.target" ];
+        after = [ "network-online.target" ];
+
+        script = ''
+          ${lib.optionalString cfg.settings.server.basicAuthEnabled ''
+            export TACHIDESK_SERVER_BASIC_AUTH_PASSWORD="$(<${cfg.settings.server.basicAuthPasswordFile})"
+          ''}
+          ${lib.getExe pkgs.envsubst} -i ${configFile} -o ${cfg.dataDir}/.local/share/Tachidesk/server.conf
+          ${lib.getExe cfg.package} -Dsuwayomi.tachidesk.config.server.rootDir=${cfg.dataDir}
+        '';
+
+        serviceConfig = {
+          User = cfg.user;
+          Group = cfg.group;
+
+          Type = "simple";
+          Restart = "on-failure";
+
+          StateDirectory = mkIf (cfg.dataDir == "/var/lib/suwayomi-server") "suwayomi-server";
+        };
+      };
+  };
+
+  meta = {
+    maintainers = with lib.maintainers; [ ratcornu ];
+    doc = ./suwayomi-server.md;
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/web-apps/tt-rss.nix b/nixpkgs/nixos/modules/services/web-apps/tt-rss.nix
index a8fb37d2c5ec..84342165c9c0 100644
--- a/nixpkgs/nixos/modules/services/web-apps/tt-rss.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/tt-rss.nix
@@ -4,6 +4,8 @@ with lib;
 let
   cfg = config.services.tt-rss;
 
+  inherit (cfg) phpPackage;
+
   configVersion = 26;
 
   dbPort = if cfg.database.port == null
@@ -26,7 +28,7 @@ let
       ;
   in pkgs.writeText "config.php" ''
     <?php
-      putenv('TTRSS_PHP_EXECUTABLE=${pkgs.php}/bin/php');
+      putenv('TTRSS_PHP_EXECUTABLE=${phpPackage}/bin/php');
 
       putenv('TTRSS_LOCK_DIRECTORY=${cfg.root}/lock');
       putenv('TTRSS_CACHE_DIR=${cfg.root}/cache');
@@ -456,6 +458,15 @@ let
         '';
       };
 
+      phpPackage = lib.mkOption {
+        type = lib.types.package;
+        default = pkgs.php;
+        defaultText = "pkgs.php";
+        description = lib.mdDoc ''
+          php package to use for php fpm and update daemon.
+        '';
+      };
+
       plugins = mkOption {
         type = types.listOf types.str;
         default = ["auth_internal" "note"];
@@ -543,7 +554,7 @@ let
     services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
       ${poolName} = {
         inherit (cfg) user;
-        phpPackage = pkgs.php81;
+        inherit phpPackage;
         settings = mapAttrs (name: mkDefault) {
           "listen.owner" = "nginx";
           "listen.group" = "nginx";
@@ -605,13 +616,13 @@ let
         description = "Tiny Tiny RSS feeds update daemon";
 
         preStart = ''
-          ${pkgs.php81}/bin/php ${cfg.root}/www/update.php --update-schema
+          ${phpPackage}/bin/php ${cfg.root}/www/update.php --update-schema --force-yes
         '';
 
         serviceConfig = {
           User = "${cfg.user}";
           Group = "tt_rss";
-          ExecStart = "${pkgs.php}/bin/php ${cfg.root}/www/update.php --daemon --quiet";
+          ExecStart = "${phpPackage}/bin/php ${cfg.root}/www/update.php --daemon --quiet";
           Restart = "on-failure";
           RestartSec = "60";
           SyslogIdentifier = "tt-rss";
diff --git a/nixpkgs/nixos/modules/services/web-apps/writefreely.nix b/nixpkgs/nixos/modules/services/web-apps/writefreely.nix
index f92afa9276e3..2e9a34897909 100644
--- a/nixpkgs/nixos/modules/services/web-apps/writefreely.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/writefreely.nix
@@ -334,8 +334,10 @@ in {
         optionalAttrs (cfg.group == "writefreely") { writefreely = { }; };
     };
 
-    systemd.tmpfiles.rules =
-      [ "d '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -" ];
+    systemd.tmpfiles.settings."10-writefreely".${cfg.stateDir}.d = {
+      inherit (cfg) user group;
+      mode = "0750";
+    };
 
     systemd.services.writefreely = {
       after = [ "network.target" ]
diff --git a/nixpkgs/nixos/modules/services/web-apps/youtrack.md b/nixpkgs/nixos/modules/services/web-apps/youtrack.md
new file mode 100644
index 000000000000..f33f482ff970
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/youtrack.md
@@ -0,0 +1,30 @@
+# YouTrack {#module-services-youtrack}
+
+YouTrack is a browser-based bug tracker, issue tracking system and project management software.
+
+## Installation {#module-services-youtrack-installation}
+
+YouTrack exposes a web GUI installer on first login.
+You need a token to access it.
+You can find this token in the log of the `youtrack` service. The log line looks like
+```
+* JetBrains YouTrack 2023.3 Configuration Wizard will be available on [http://127.0.0.1:8090/?wizard_token=somelongtoken] after start
+```
+
+## Upgrade from 2022.3 to 2023.x {#module-services-youtrack-upgrade-2022_3-2023_1}
+
+Starting with YouTrack 2023.1, JetBrains no longer distributes it as as JAR.
+The new distribution with the JetBrains Launcher as a ZIP changed the basic data structure and also some configuration parameters.
+Check out https://www.jetbrains.com/help/youtrack/server/YouTrack-Java-Start-Parameters.html for more information on the new configuration options.
+When upgrading to YouTrack 2023.1 or higher, a migration script will move the old state directory to `/var/lib/youtrack/2022_3` as a backup.
+A one-time manual update is required:
+
+1. Before you update take a backup of your YouTrack instance!
+2. Migrate the options you set in `services.youtrack.extraParams` and `services.youtrack.jvmOpts` to `services.youtrack.generalParameters` and `services.youtrack.environmentalParameters` (see the examples and [the YouTrack docs](https://www.jetbrains.com/help/youtrack/server/2023.3/YouTrack-Java-Start-Parameters.html))
+2. To start the upgrade set `services.youtrack.package = pkgs.youtrack`
+3. YouTrack then starts in upgrade mode, meaning you need to obtain the wizard token as above
+4. Select you want to **Upgrade** YouTrack
+5. As source you select `/var/lib/youtrack/2022_3/teamsysdata/` (adopt if you have a different state path)
+6. Change the data directory location to `/var/lib/youtrack/data/`. The other paths should already be right.
+
+If you migrate a larger YouTrack instance, it might be useful to set `-Dexodus.entityStore.refactoring.forceAll=true` in `services.youtrack.generalParameters` for the first startup of YouTrack 2023.x.
diff --git a/nixpkgs/nixos/modules/services/web-apps/youtrack.nix b/nixpkgs/nixos/modules/services/web-apps/youtrack.nix
index 79e1d12e0abb..08e180b520f0 100644
--- a/nixpkgs/nixos/modules/services/web-apps/youtrack.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/youtrack.nix
@@ -1,130 +1,224 @@
 { config, lib, pkgs, ... }:
 
-with lib;
-
 let
   cfg = config.services.youtrack;
-
-  extraAttr = concatStringsSep " " (mapAttrsToList (k: v: "-D${k}=${v}") (stdParams // cfg.extraParams));
-  mergeAttrList = lib.foldl' lib.mergeAttrs {};
-
-  stdParams = mergeAttrList [
-    (optionalAttrs (cfg.baseUrl != null) {
-      "jetbrains.youtrack.baseUrl" = cfg.baseUrl;
-    })
-    {
-    "java.aws.headless" = "true";
-    "jetbrains.youtrack.disableBrowser" = "true";
-    }
-  ];
 in
 {
-  options.services.youtrack = {
+  imports = [
+    (lib.mkRenamedOptionModule [ "services" "youtrack" "baseUrl" ] [ "services" "youtrack" "environmentalParameters" "base-url" ])
+    (lib.mkRenamedOptionModule [ "services" "youtrack" "port" ] [ "services" "youtrack" "environmentalParameters" "listen-port" ])
+    (lib.mkRemovedOptionModule [ "services" "youtrack" "maxMemory" ] "Please instead use `services.youtrack.generalParameters`.")
+    (lib.mkRemovedOptionModule [ "services" "youtrack" "maxMetaspaceSize" ] "Please instead use `services.youtrack.generalParameters`.")
+  ];
 
-    enable = mkEnableOption (lib.mdDoc "YouTrack service");
+  options.services.youtrack = {
+    enable = lib.mkEnableOption (lib.mdDoc "YouTrack service");
 
-    address = mkOption {
+    address = lib.mkOption {
       description = lib.mdDoc ''
         The interface youtrack will listen on.
       '';
       default = "127.0.0.1";
-      type = types.str;
+      type = lib.types.str;
     };
 
-    baseUrl = mkOption {
-      description = lib.mdDoc ''
-        Base URL for youtrack. Will be auto-detected and stored in database.
-      '';
-      type = types.nullOr types.str;
-      default = null;
-    };
-
-    extraParams = mkOption {
+    extraParams = lib.mkOption {
       default = {};
       description = lib.mdDoc ''
-        Extra parameters to pass to youtrack. See
+        Extra parameters to pass to youtrack.
+        Use to configure YouTrack 2022.x, deprecated with YouTrack 2023.x. Use `services.youtrack.generalParameters`.
         https://www.jetbrains.com/help/youtrack/standalone/YouTrack-Java-Start-Parameters.html
         for more information.
       '';
-      example = literalExpression ''
+      example = lib.literalExpression ''
         {
           "jetbrains.youtrack.overrideRootPassword" = "tortuga";
         }
       '';
-      type = types.attrsOf types.str;
+      type = lib.types.attrsOf lib.types.str;
+      visible = false;
     };
 
-    package = mkPackageOption pkgs "youtrack" { };
-
-    port = mkOption {
+    package = lib.mkOption {
       description = lib.mdDoc ''
-        The port youtrack will listen on.
+        Package to use.
       '';
-      default = 8080;
-      type = types.port;
+      type = lib.types.package;
+      default = null;
+      relatedPackages = [ "youtrack_2022_3" "youtrack" ];
     };
 
-    statePath = mkOption {
+
+    statePath = lib.mkOption {
       description = lib.mdDoc ''
-        Where to keep the youtrack database.
+        Path were the YouTrack state is stored.
+        To this path the base version (e.g. 2023_1) of the used package will be appended.
       '';
-      type = types.path;
+      type = lib.types.path;
       default = "/var/lib/youtrack";
     };
 
-    virtualHost = mkOption {
+    virtualHost = lib.mkOption {
       description = lib.mdDoc ''
         Name of the nginx virtual host to use and setup.
         If null, do not setup anything.
       '';
       default = null;
-      type = types.nullOr types.str;
+      type = lib.types.nullOr lib.types.str;
     };
 
-    jvmOpts = mkOption {
+    jvmOpts = lib.mkOption {
       description = lib.mdDoc ''
         Extra options to pass to the JVM.
+        Only has a use with YouTrack 2022.x, deprecated with YouTrack 2023.x. Use `serivces.youtrack.generalParameters`.
         See https://www.jetbrains.com/help/youtrack/standalone/Configure-JVM-Options.html
         for more information.
       '';
-      type = types.separatedString " ";
-      example = "-XX:MetaspaceSize=250m";
+      type = lib.types.separatedString " ";
+      example = "--J-XX:MetaspaceSize=250m";
       default = "";
+      visible = false;
     };
 
-    maxMemory = mkOption {
+    autoUpgrade = lib.mkOption {
+      type = lib.types.bool;
+      default = true;
+      description = lib.mdDoc "Whether YouTrack should auto upgrade it without showing the upgrade dialog.";
+    };
+
+    generalParameters = lib.mkOption {
+      type = with lib.types; listOf str;
       description = lib.mdDoc ''
-        Maximum Java heap size
+        General configuration parameters and other JVM options.
+        Only has an effect for YouTrack 2023.x.
+        See https://www.jetbrains.com/help/youtrack/server/2023.3/youtrack-java-start-parameters.html#general-parameters
+        for more information.
       '';
-      type = types.str;
-      default = "1g";
+      example = lib.literalExpression ''
+        [
+          "-Djetbrains.youtrack.admin.restore=true"
+          "-Xmx1024m"
+        ];
+      '';
+      default = [];
     };
 
-    maxMetaspaceSize = mkOption {
+    environmentalParameters = lib.mkOption {
+      type = lib.types.submodule {
+        freeformType = with lib.types; attrsOf (oneOf [ int str port ]);
+        options = {
+          listen-address = lib.mkOption {
+            type = lib.types.str;
+            default = "0.0.0.0";
+            description = lib.mdDoc "The interface YouTrack will listen on.";
+          };
+          listen-port = lib.mkOption {
+            type = lib.types.port;
+            default = 8080;
+            description = lib.mdDoc "The port YouTrack will listen on.";
+          };
+        };
+      };
       description = lib.mdDoc ''
-        Maximum java Metaspace memory.
+        Environmental configuration parameters, set imperatively. The values doesn't get removed, when removed in Nix.
+        Only has an effect for YouTrack 2023.x.
+        See https://www.jetbrains.com/help/youtrack/server/2023.3/youtrack-java-start-parameters.html#environmental-parameters
+        for more information.
+      '';
+      example = lib.literalExpression ''
+        {
+          secure-mode = "tls";
+        }
       '';
-      type = types.str;
-      default = "350m";
+      default = {};
     };
   };
 
-  config = mkIf cfg.enable {
-
-    systemd.services.youtrack = {
-      environment.HOME = cfg.statePath;
-      environment.YOUTRACK_JVM_OPTS = "${extraAttr}";
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-      path = with pkgs; [ unixtools.hostname ];
-      serviceConfig = {
-        Type = "simple";
-        User = "youtrack";
-        Group = "youtrack";
-        Restart = "on-failure";
-        ExecStart = ''${cfg.package}/bin/youtrack --J-Xmx${cfg.maxMemory} --J-XX:MaxMetaspaceSize=${cfg.maxMetaspaceSize} ${cfg.jvmOpts} ${cfg.address}:${toString cfg.port}'';
+  config = lib.mkIf cfg.enable {
+    warnings = lib.optional (lib.versions.major cfg.package.version <= "2022")
+      "YouTrack 2022.x is deprecated. See https://nixos.org/manual/nixos/unstable/index.html#module-services-youtrack for details on how to upgrade."
+    ++ lib.optional (cfg.extraParams != {} && (lib.versions.major cfg.package.version >= "2023"))
+      "'services.youtrack.extraParams' is deprecated and has no effect on YouTrack 2023.x and newer. Please migrate to 'services.youtrack.generalParameters'"
+    ++ lib.optional (cfg.jvmOpts != "" && (lib.versions.major cfg.package.version >= "2023"))
+      "'services.youtrack.jvmOpts' is deprecated and has no effect on YouTrack 2023.x and newer. Please migrate to 'services.youtrack.generalParameters'";
+
+    # XXX: Drop all version feature switches at the point when we consider YT 2022.3 as outdated.
+    services.youtrack.package = lib.mkDefault (
+      if lib.versionAtLeast config.system.stateVersion "24.11" then pkgs.youtrack
+      else pkgs.youtrack_2022_3
+    );
+
+    services.youtrack.generalParameters = lib.optional (lib.versions.major cfg.package.version >= "2023")
+      "-Ddisable.configuration.wizard.on.upgrade=${lib.boolToString cfg.autoUpgrade}"
+      ++ (lib.mapAttrsToList (k: v: "-D${k}=${v}") cfg.extraParams);
+
+    systemd.services.youtrack = let
+      service_jar = let
+        mergeAttrList = lib.foldl' lib.mergeAttrs {};
+        stdParams = mergeAttrList [
+          (lib.optionalAttrs (cfg.environmentalParameters ? base-url && cfg.environmentalParameters.base-url != null) {
+            "jetbrains.youtrack.baseUrl" = cfg.environmentalParameters.base-url;
+          })
+          {
+          "java.aws.headless" = "true";
+          "jetbrains.youtrack.disableBrowser" = "true";
+          }
+        ];
+        extraAttr = lib.concatStringsSep " " (lib.mapAttrsToList (k: v: "-D${k}=${v}") (stdParams // cfg.extraParams));
+      in {
+        environment.HOME = cfg.statePath;
+        environment.YOUTRACK_JVM_OPTS = "${extraAttr}";
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        path = with pkgs; [ unixtools.hostname ];
+        serviceConfig = {
+          Type = "simple";
+          User = "youtrack";
+          Group = "youtrack";
+          Restart = "on-failure";
+          ExecStart = ''${cfg.package}/bin/youtrack ${cfg.jvmOpts} ${cfg.environmentalParameters.listen-address}:${toString cfg.environmentalParameters.listen-port}'';
+        };
       };
-    };
+      service_zip = let
+        jvmoptions = pkgs.writeTextFile {
+          name = "youtrack.jvmoptions";
+          text = (lib.concatStringsSep "\n" cfg.generalParameters);
+        };
+
+        package = cfg.package.override {
+          statePath = cfg.statePath;
+        };
+      in {
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        path = with pkgs; [ unixtools.hostname ];
+        preStart = ''
+          # This detects old (i.e. <= 2022.3) installations that were not migrated yet
+          # and migrates them to the new state directory style
+          if [[ -d ${cfg.statePath}/teamsysdata ]] && [[ ! -d ${cfg.statePath}/2022_3 ]]
+          then
+            mkdir -p ${cfg.statePath}/2022_3
+            mv ${cfg.statePath}/teamsysdata ${cfg.statePath}/2022_3
+            mv ${cfg.statePath}/.youtrack ${cfg.statePath}/2022_3
+          fi
+          mkdir -p ${cfg.statePath}/{backups,conf,data,logs,temp}
+          ${pkgs.coreutils}/bin/ln -fs ${jvmoptions} ${cfg.statePath}/conf/youtrack.jvmoptions
+          ${package}/bin/youtrack configure ${lib.concatStringsSep " " (lib.mapAttrsToList (name: value: "--${name}=${toString value}") cfg.environmentalParameters )}
+        '';
+        serviceConfig = lib.mkMerge [
+          {
+            Type = "simple";
+            User = "youtrack";
+            Group = "youtrack";
+            Restart = "on-failure";
+            ExecStart = "${package}/bin/youtrack run";
+          }
+          (lib.mkIf (cfg.statePath == "/var/lib/youtrack") {
+            StateDirectory = "youtrack";
+          })
+        ];
+      };
+    in if (lib.versions.major cfg.package.version >= "2023") then service_zip else service_jar;
 
     users.users.youtrack = {
       description = "Youtrack service user";
@@ -136,8 +230,8 @@ in
 
     users.groups.youtrack = {};
 
-    services.nginx = mkIf (cfg.virtualHost != null) {
-      upstreams.youtrack.servers."${cfg.address}:${toString cfg.port}" = {};
+    services.nginx = lib.mkIf (cfg.virtualHost != null) {
+      upstreams.youtrack.servers."${cfg.address}:${toString cfg.environmentalParameters.listen-port}" = {};
       virtualHosts.${cfg.virtualHost}.locations = {
         "/" = {
           proxyPass = "http://youtrack";
@@ -166,9 +260,10 @@ in
             proxy_set_header X-Forwarded-Proto $scheme;
           '';
         };
-
       };
     };
-
   };
+
+  meta.doc = ./youtrack.md;
+  meta.maintainers = [ lib.maintainers.leona ];
 }
diff --git a/nixpkgs/nixos/modules/services/web-servers/agate.nix b/nixpkgs/nixos/modules/services/web-servers/agate.nix
index dce425035ff7..e03174c87945 100644
--- a/nixpkgs/nixos/modules/services/web-servers/agate.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/agate.nix
@@ -71,6 +71,7 @@ in
     systemd.services.agate = {
       description = "Agate";
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = [ "network.target" "network-online.target" ];
 
       script =
diff --git a/nixpkgs/nixos/modules/services/web-servers/mighttpd2.nix b/nixpkgs/nixos/modules/services/web-servers/mighttpd2.nix
index bdd6d8b62aa3..bb75dc4f2ff4 100644
--- a/nixpkgs/nixos/modules/services/web-servers/mighttpd2.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/mighttpd2.nix
@@ -101,6 +101,7 @@ in {
       ];
     systemd.services.mighttpd2 = {
       description = "Mighttpd2 web server";
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
       serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/web-servers/minio.nix b/nixpkgs/nixos/modules/services/web-servers/minio.nix
index 6431db250476..be6946657e23 100644
--- a/nixpkgs/nixos/modules/services/web-servers/minio.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/minio.nix
@@ -98,6 +98,7 @@ in
 
       services.minio = {
         description = "Minio Object Storage";
+        wants = [ "network-online.target" ];
         after = [ "network-online.target" ];
         wantedBy = [ "multi-user.target" ];
         serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
index 6799de6c7d96..93b1a3fdfadd 100644
--- a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
@@ -361,10 +361,12 @@ let
             ${optionalString (vhost.acmeFallbackHost != null) "try_files $uri @acme-fallback;"}
             ${optionalString (vhost.acmeRoot != null) "root ${vhost.acmeRoot};"}
             auth_basic off;
+            auth_request off;
           }
           ${optionalString (vhost.acmeFallbackHost != null) ''
             location @acme-fallback {
               auth_basic off;
+              auth_request off;
               proxy_pass http://${vhost.acmeFallbackHost};
             }
           ''}
diff --git a/nixpkgs/nixos/modules/services/web-servers/traefik.nix b/nixpkgs/nixos/modules/services/web-servers/traefik.nix
index cc2c680b3342..fc9eb504ebf8 100644
--- a/nixpkgs/nixos/modules/services/web-servers/traefik.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/traefik.nix
@@ -144,6 +144,7 @@ in {
 
     systemd.services.traefik = {
       description = "Traefik web server";
+      wants = [ "network-online.target" ];
       after = [ "network-online.target" ];
       wantedBy = [ "multi-user.target" ];
       startLimitIntervalSec = 86400;
diff --git a/nixpkgs/nixos/modules/services/web-servers/ttyd.nix b/nixpkgs/nixos/modules/services/web-servers/ttyd.nix
index 3b1d87ccb483..e545869ca432 100644
--- a/nixpkgs/nixos/modules/services/web-servers/ttyd.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/ttyd.nix
@@ -180,10 +180,11 @@ in
         # Runs login which needs to be run as root
         # login: Cannot possibly work without effective root
         User = "root";
+        LoadCredential = lib.optionalString (cfg.passwordFile != null) "TTYD_PASSWORD_FILE:${cfg.passwordFile}";
       };
 
       script = if cfg.passwordFile != null then ''
-        PASSWORD=$(cat ${escapeShellArg cfg.passwordFile})
+        PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/TTYD_PASSWORD_FILE")
         ${pkgs.ttyd}/bin/ttyd ${lib.escapeShellArgs args} \
           --credential ${escapeShellArg cfg.username}:"$PASSWORD" \
           ${pkgs.shadow}/bin/login
diff --git a/nixpkgs/nixos/modules/services/web-servers/zope2.nix b/nixpkgs/nixos/modules/services/web-servers/zope2.nix
index a17fe6bc2082..29731b29eea4 100644
--- a/nixpkgs/nixos/modules/services/web-servers/zope2.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/zope2.nix
@@ -147,7 +147,7 @@ in
               name = "zope2-${name}-env";
               paths = [
                 pkgs.python27
-                pkgs.python27Packages.recursivePthLoader
+                pkgs.python27Packages.recursive-pth-loader
                 pkgs.python27Packages."plone.recipe.zope2instance"
               ] ++ attrValues pkgs.python27.modules
                 ++ opts.packages;
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/budgie.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/budgie.nix
index de4b2c0e50f5..463c45675cee 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/budgie.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/budgie.nix
@@ -118,9 +118,7 @@ in {
         (budgie.budgie-desktop-with-plugins.override { plugins = cfg.extraPlugins; })
         budgie.budgie-desktop-view
         budgie.budgie-screensaver
-
-        # Required by the Budgie Desktop session.
-        (gnome.gnome-session.override { gnomeShellSupport = false; })
+        budgie.budgie-session
 
         # Required by Budgie Menu.
         gnome-menus
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/deepin.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/deepin.nix
index 7fdd50b1ed26..7d3acada6073 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/deepin.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/deepin.nix
@@ -96,18 +96,10 @@ in
         "/share/dde-daemon"
         "/share/dsg"
         "/share/deepin-themes"
+        "/share/deepin"
       ];
 
       environment.etc = {
-        "distribution.info".text = ''
-          [Distribution]
-          Name=NixOS
-          WebsiteName=www.nixos.org
-          Website=https://www.nixos.org
-          Logo=${pkgs.nixos-icons}/share/icons/hicolor/96x96/apps/nix-snowflake.png
-          LogoLight=${pkgs.nixos-icons}/share/icons/hicolor/32x32/apps/nix-snowflake.png
-          LogoTransparent=${pkgs.deepin.deepin-desktop-base}/share/pixmaps/distribution_logo_transparent.svg
-        '';
         "deepin-installer.conf".text = ''
           system_info_vendor_name="Copyright (c) 2003-2023 NixOS contributors"
         '';
@@ -156,6 +148,7 @@ in
             deepin-sound-theme
             deepin-gtk-theme
             deepin-wallpapers
+            deepin-desktop-base
 
             startdde
             dde-dock
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/phosh.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/phosh.nix
index 5392ab73aeb8..75e02130addc 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/phosh.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/phosh.nix
@@ -186,6 +186,21 @@ in
         UtmpIdentifier = "tty7";
         UtmpMode = "user";
       };
+      environment = {
+        # We are running without a display manager, so need to provide
+        # a value for XDG_CURRENT_DESKTOP.
+        #
+        # Among other things, this variable influences:
+        #  - visibility of desktop entries with "OnlyShowIn=Phosh;"
+        #    https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.5.html#key-onlyshowin
+        #  - the chosen xdg-desktop-portal configuration.
+        #    https://flatpak.github.io/xdg-desktop-portal/docs/portals.conf.html
+        XDG_CURRENT_DESKTOP = "Phosh:GNOME";
+        # pam_systemd uses these to identify the session in logind.
+        # https://www.freedesktop.org/software/systemd/man/latest/pam_systemd.html#desktop=
+        XDG_SESSION_DESKTOP = "phosh";
+        XDG_SESSION_TYPE = "wayland";
+      };
     };
 
     environment.systemPackages = [
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
index fc9de2500ba4..0eb492ce4684 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -185,6 +185,8 @@ in
         };
       };
 
+      qt.enable = true;
+
       environment.systemPackages =
         with pkgs.plasma5Packages;
         let
@@ -253,6 +255,9 @@ in
             plasma-integration
             polkit-kde-agent
 
+            qqc2-breeze-style
+            qqc2-desktop-style
+
             plasma-desktop
             plasma-workspace
             plasma-workspace-wallpapers
@@ -379,6 +384,7 @@ in
       system.userActivationScripts.plasmaSetup = activationScript;
 
       programs.firefox.nativeMessagingHosts.packages = [ pkgs.plasma5Packages.plasma-browser-integration ];
+      programs.chromium.enablePlasmaBrowserIntegration = true;
     })
 
     (mkIf (cfg.kwinrc != {}) {
@@ -480,7 +486,7 @@ in
           pkgs.maliit-framework
           pkgs.maliit-keyboard
         ]
-        ++ lib.optionals (cfg.mobile.installRecommendedSoftware) (with libsForQt5.plasmaMobileGear;[
+        ++ lib.optionals (cfg.mobile.installRecommendedSoftware) (with pkgs.plasma5Packages.plasmaMobileGear; [
           # Additional software made for Plasma Mobile.
           alligator
           angelfish
diff --git a/nixpkgs/nixos/modules/services/x11/xserver.nix b/nixpkgs/nixos/modules/services/x11/xserver.nix
index 36f25d5547ca..38fb1074fcdf 100644
--- a/nixpkgs/nixos/modules/services/x11/xserver.nix
+++ b/nixpkgs/nixos/modules/services/x11/xserver.nix
@@ -710,9 +710,9 @@ in
           '';
         }
       # Needed since 1.18; see https://bugs.freedesktop.org/show_bug.cgi?id=89023#c5
-      // (let cfgPath = "/X11/xorg.conf.d/10-evdev.conf"; in
+      // (let cfgPath = "X11/xorg.conf.d/10-evdev.conf"; in
         {
-          ${cfgPath}.source = xorg.xf86inputevdev.out + "/share" + cfgPath;
+          ${cfgPath}.source = xorg.xf86inputevdev.out + "/share/" + cfgPath;
         });
 
     environment.systemPackages = utils.removePackagesByName
diff --git a/nixpkgs/nixos/modules/system/boot/clevis.md b/nixpkgs/nixos/modules/system/boot/clevis.md
index 91eb728a919e..dcbf55de60a8 100644
--- a/nixpkgs/nixos/modules/system/boot/clevis.md
+++ b/nixpkgs/nixos/modules/system/boot/clevis.md
@@ -14,20 +14,20 @@ JWE files have to be created through the clevis command line. 3 types of policie
 
 Secrets are pinned against the presence of a TPM2 device, for example:
 ```
-echo hi | clevis encrypt tpm2 '{}' > hi.jwe
+echo -n hi | clevis encrypt tpm2 '{}' > hi.jwe
 ```
 2) Tang policies
 
 Secrets are pinned against the presence of a Tang server, for example:
 ```
-echo hi | clevis encrypt tang '{"url": "http://tang.local"}' > hi.jwe
+echo -n hi | clevis encrypt tang '{"url": "http://tang.local"}' > hi.jwe
 ```
 
 3) Shamir Secret Sharing
 
 Using Shamir's Secret Sharing ([sss](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing)), secrets are pinned using a combination of the two preceding policies. For example:
 ```
-echo hi | clevis encrypt sss \
+echo -n hi | clevis encrypt sss \
 '{"t": 2, "pins": {"tpm2": {"pcr_ids": "0"}, "tang": {"url": "http://tang.local"}}}' \
 > hi.jwe
 ```
diff --git a/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl
index d1e7a0cb8178..6f0f62546a01 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -136,7 +136,6 @@ sub GetFs {
         chomp $fs;
         my @fields = split / /, $fs;
         my $mountPoint = $fields[4];
-        next unless -d $mountPoint;
         my @mountOptions = split /,/, $fields[5];
 
         # Skip the optional fields.
@@ -155,6 +154,11 @@ sub GetFs {
 
         # Is it better than our current match?
         if (length($mountPoint) > length($bestFs->mount)) {
+
+            # -d performs a stat, which can hang forever on network file systems,
+            # so we only make this call last, when it's likely that this is the mount point we need.
+            next unless -d $mountPoint;
+
             $bestFs = Fs->new(device => $device, type => $fsType, mount => $mountPoint);
         }
     }
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 6cd46f30373b..a9978d7adf80 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
@@ -15,6 +15,19 @@ import json
 from typing import NamedTuple, Dict, List
 from dataclasses import dataclass
 
+# These values will be replaced with actual values during the package build
+EFI_SYS_MOUNT_POINT = "@efiSysMountPoint@"
+TIMEOUT = "@timeout@"
+EDITOR = "@editor@" == "1"
+CONSOLE_MODE = "@consoleMode@"
+BOOTSPEC_TOOLS = "@bootspecTools@"
+DISTRO_NAME = "@distroName@"
+NIX = "@nix@"
+SYSTEMD = "@systemd@"
+CONFIGURATION_LIMIT = int("@configurationLimit@")
+CAN_TOUCH_EFI_VARIABLES = "@canTouchEfiVariables@"
+GRACEFUL = "@graceful@"
+COPY_EXTRA_FILES = "@copyExtraFiles@"
 
 @dataclass
 class BootSpec:
@@ -29,7 +42,6 @@ class BootSpec:
     initrdSecrets: str | None = None
 
 
-
 libc = ctypes.CDLL("libc.so.6")
 
 class SystemIdentifier(NamedTuple):
@@ -75,16 +87,16 @@ def generation_conf_filename(profile: str | None, generation: int, specialisatio
 
 
 def write_loader_conf(profile: str | None, generation: int, specialisation: str | None) -> None:
-    with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f:
-        if "@timeout@" != "":
-            f.write("timeout @timeout@\n")
+    with open(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf.tmp", 'w') as f:
+        if TIMEOUT != "":
+            f.write(f"timeout {TIMEOUT}\n")
         f.write("default %s\n" % generation_conf_filename(profile, generation, specialisation))
-        if not @editor@:
+        if not EDITOR:
             f.write("editor 0\n")
-        f.write("console-mode @consoleMode@\n")
+        f.write(f"console-mode {CONSOLE_MODE}\n")
         f.flush()
         os.fsync(f.fileno())
-    os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf")
+    os.rename(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf.tmp", f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf")
 
 
 def get_bootspec(profile: str | None, generation: int) -> BootSpec:
@@ -95,7 +107,7 @@ def get_bootspec(profile: str | None, generation: int) -> BootSpec:
         bootspec_json = json.load(boot_json_f)
     else:
         boot_json_str = subprocess.check_output([
-        "@bootspecTools@/bin/synthesize",
+        f"{BOOTSPEC_TOOLS}/bin/synthesize",
         "--version",
         "1",
         system_directory,
@@ -116,7 +128,7 @@ def copy_from_file(file: str, dry_run: bool = False) -> str:
     store_dir = os.path.basename(os.path.dirname(store_file_path))
     efi_file_path = "/efi/nixos/%s-%s.efi" % (store_dir, suffix)
     if not dry_run:
-        copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path))
+        copy_if_not_exists(store_file_path, f"{EFI_SYS_MOUNT_POINT}%s" % (efi_file_path))
     return efi_file_path
 
 def write_entry(profile: str | None, generation: int, specialisation: str | None,
@@ -126,13 +138,14 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None
     kernel = copy_from_file(bootspec.kernel)
     initrd = copy_from_file(bootspec.initrd)
 
-    title = "@distroName@{profile}{specialisation}".format(
+    title = "{name}{profile}{specialisation}".format(
+        name=DISTRO_NAME,
         profile=" [" + profile + "]" if profile else "",
         specialisation=" (%s)" % specialisation if specialisation else "")
 
     try:
         if bootspec.initrdSecrets is not None:
-            subprocess.check_call([bootspec.initrdSecrets, "@efiSysMountPoint@%s" % (initrd)])
+            subprocess.check_call([bootspec.initrdSecrets, f"{EFI_SYS_MOUNT_POINT}%s" % (initrd)])
     except subprocess.CalledProcessError:
         if current:
             print("failed to create initrd secrets!", file=sys.stderr)
@@ -142,7 +155,7 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None
                   f'for "{title} - Configuration {generation}", an older generation', file=sys.stderr)
             print("note: this is normal after having removed "
                   "or renamed a file in `boot.initrd.secrets`", file=sys.stderr)
-    entry_file = "@efiSysMountPoint@/loader/entries/%s" % (
+    entry_file = f"{EFI_SYS_MOUNT_POINT}/loader/entries/%s" % (
         generation_conf_filename(profile, generation, specialisation))
     tmp_path = "%s.tmp" % (entry_file)
     kernel_params = "init=%s " % bootspec.init
@@ -167,7 +180,7 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None
 
 def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
     gen_list = subprocess.check_output([
-        "@nix@/bin/nix-env",
+        f"{NIX}/bin/nix-env",
         "--list-generations",
         "-p",
         "/nix/var/nix/profiles/%s" % ("system-profiles/" + profile if profile else "system"),
@@ -176,7 +189,7 @@ def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
     gen_lines = gen_list.split('\n')
     gen_lines.pop()
 
-    configurationLimit = @configurationLimit@
+    configurationLimit = CONFIGURATION_LIMIT
     configurations = [
         SystemIdentifier(
             profile=profile,
@@ -189,14 +202,14 @@ def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
 
 
 def remove_old_entries(gens: list[SystemIdentifier]) -> None:
-    rex_profile = re.compile(r"^@efiSysMountPoint@/loader/entries/nixos-(.*)-generation-.*\.conf$")
-    rex_generation = re.compile(r"^@efiSysMountPoint@/loader/entries/nixos.*-generation-([0-9]+)(-specialisation-.*)?\.conf$")
+    rex_profile = re.compile(r"^" + re.escape(EFI_SYS_MOUNT_POINT) + "/loader/entries/nixos-(.*)-generation-.*\.conf$")
+    rex_generation = re.compile(r"^" + re.escape(EFI_SYS_MOUNT_POINT) + "/loader/entries/nixos.*-generation-([0-9]+)(-specialisation-.*)?\.conf$")
     known_paths = []
     for gen in gens:
         bootspec = get_bootspec(gen.profile, gen.generation)
         known_paths.append(copy_from_file(bootspec.kernel, True))
         known_paths.append(copy_from_file(bootspec.initrd, True))
-    for path in glob.iglob("@efiSysMountPoint@/loader/entries/nixos*-generation-[1-9]*.conf"):
+    for path in glob.iglob(f"{EFI_SYS_MOUNT_POINT}/loader/entries/nixos*-generation-[1-9]*.conf"):
         if rex_profile.match(path):
             prof = rex_profile.sub(r"\1", path)
         else:
@@ -207,7 +220,7 @@ def remove_old_entries(gens: list[SystemIdentifier]) -> None:
             continue
         if not (prof, gen_number, None) in gens:
             os.unlink(path)
-    for path in glob.iglob("@efiSysMountPoint@/efi/nixos/*"):
+    for path in glob.iglob(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/*"):
         if not path in known_paths and not os.path.isdir(path):
             os.unlink(path)
 
@@ -230,7 +243,7 @@ def install_bootloader(args: argparse.Namespace) -> None:
         # Since systemd version 232 a machine ID is required and it might not
         # be there on newly installed systems, so let's generate one so that
         # bootctl can find it and we can also pass it to write_entry() later.
-        cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"]
+        cmd = [f"{SYSTEMD}/bin/systemd-machine-id-setup", "--print"]
         machine_id = subprocess.run(
           cmd, text=True, check=True, stdout=subprocess.PIPE
         ).stdout.rstrip()
@@ -242,22 +255,22 @@ def install_bootloader(args: argparse.Namespace) -> None:
     # flags to pass to bootctl install/update
     bootctl_flags = []
 
-    if "@canTouchEfiVariables@" != "1":
+    if CAN_TOUCH_EFI_VARIABLES != "1":
         bootctl_flags.append("--no-variables")
 
-    if "@graceful@" == "1":
+    if GRACEFUL == "1":
         bootctl_flags.append("--graceful")
 
     if os.getenv("NIXOS_INSTALL_BOOTLOADER") == "1":
         # bootctl uses fopen() with modes "wxe" and fails if the file exists.
-        if os.path.exists("@efiSysMountPoint@/loader/loader.conf"):
-            os.unlink("@efiSysMountPoint@/loader/loader.conf")
+        if os.path.exists(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf"):
+            os.unlink(f"{EFI_SYS_MOUNT_POINT}/loader/loader.conf")
 
-        subprocess.check_call(["@systemd@/bin/bootctl", "--esp-path=@efiSysMountPoint@"] + bootctl_flags + ["install"])
+        subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["install"])
     else:
         # Update bootloader to latest if needed
-        available_out = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[2]
-        installed_out = subprocess.check_output(["@systemd@/bin/bootctl", "--esp-path=@efiSysMountPoint@", "status"], universal_newlines=True)
+        available_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", "--version"], universal_newlines=True).split()[2]
+        installed_out = subprocess.check_output([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}", "status"], universal_newlines=True)
 
         # See status_binaries() in systemd bootctl.c for code which generates this
         installed_match = re.search(r"^\W+File:.*/EFI/(?:BOOT|systemd)/.*\.efi \(systemd-boot ([\d.]+[^)]*)\)$",
@@ -276,10 +289,10 @@ def install_bootloader(args: argparse.Namespace) -> None:
 
         if installed_version < available_version:
             print("updating systemd-boot from %s to %s" % (installed_version, available_version))
-            subprocess.check_call(["@systemd@/bin/bootctl", "--esp-path=@efiSysMountPoint@"] + bootctl_flags + ["update"])
+            subprocess.check_call([f"{SYSTEMD}/bin/bootctl", f"--esp-path={EFI_SYS_MOUNT_POINT}"] + bootctl_flags + ["update"])
 
-    os.makedirs("@efiSysMountPoint@/efi/nixos", exist_ok=True)
-    os.makedirs("@efiSysMountPoint@/loader/entries", exist_ok=True)
+    os.makedirs(f"{EFI_SYS_MOUNT_POINT}/efi/nixos", exist_ok=True)
+    os.makedirs(f"{EFI_SYS_MOUNT_POINT}/loader/entries", exist_ok=True)
 
     gens = get_generations()
     for profile in get_profiles():
@@ -302,9 +315,9 @@ def install_bootloader(args: argparse.Namespace) -> None:
             else:
                 raise e
 
-    for root, _, files in os.walk('@efiSysMountPoint@/efi/nixos/.extra-files', topdown=False):
-        relative_root = root.removeprefix("@efiSysMountPoint@/efi/nixos/.extra-files").removeprefix("/")
-        actual_root = os.path.join("@efiSysMountPoint@", relative_root)
+    for root, _, files in os.walk(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/.extra-files", topdown=False):
+        relative_root = root.removeprefix(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/.extra-files").removeprefix("/")
+        actual_root = os.path.join(f"{EFI_SYS_MOUNT_POINT}", relative_root)
 
         for file in files:
             actual_file = os.path.join(actual_root, file)
@@ -317,14 +330,14 @@ def install_bootloader(args: argparse.Namespace) -> None:
             os.rmdir(actual_root)
         os.rmdir(root)
 
-    os.makedirs("@efiSysMountPoint@/efi/nixos/.extra-files", exist_ok=True)
+    os.makedirs(f"{EFI_SYS_MOUNT_POINT}/efi/nixos/.extra-files", exist_ok=True)
 
-    subprocess.check_call("@copyExtraFiles@")
+    subprocess.check_call(COPY_EXTRA_FILES)
 
 
 def main() -> None:
-    parser = argparse.ArgumentParser(description='Update @distroName@-related systemd-boot files')
-    parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default @distroName@ config to boot')
+    parser = argparse.ArgumentParser(description=f"Update {DISTRO_NAME}-related systemd-boot files")
+    parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help=f"The default {DISTRO_NAME} config to boot")
     args = parser.parse_args()
 
     try:
@@ -334,9 +347,9 @@ def main() -> None:
         # it can leave the system in an unbootable state, when a crash/outage
         # happens shortly after an update. To decrease the likelihood of this
         # event sync the efi filesystem after each update.
-        rc = libc.syncfs(os.open("@efiSysMountPoint@", os.O_RDONLY))
+        rc = libc.syncfs(os.open(f"{EFI_SYS_MOUNT_POINT}", os.O_RDONLY))
         if rc != 0:
-            print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr)
+            print(f"could not sync {EFI_SYS_MOUNT_POINT}: {os.strerror(rc)}", file=sys.stderr)
 
 
 if __name__ == '__main__':
diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
index 9d55c21077d1..ea4553b8208f 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
+++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
@@ -22,11 +22,9 @@ let
 
     timeout = optionalString (config.boot.loader.timeout != null) config.boot.loader.timeout;
 
-    editor = if cfg.editor then "True" else "False";
-
     configurationLimit = if cfg.configurationLimit == null then 0 else cfg.configurationLimit;
 
-    inherit (cfg) consoleMode graceful;
+    inherit (cfg) consoleMode graceful editor;
 
     inherit (efi) efiSysMountPoint canTouchEfiVariables;
 
@@ -54,17 +52,18 @@ let
   checkedSystemdBootBuilder = pkgs.runCommand "systemd-boot" {
     nativeBuildInputs = [ pkgs.mypy ];
   } ''
-    install -m755 ${systemdBootBuilder} $out
+    mkdir -p $out/bin
+    install -m755 ${systemdBootBuilder} $out/bin/systemd-boot-builder
     mypy \
       --no-implicit-optional \
       --disallow-untyped-calls \
       --disallow-untyped-defs \
-      $out
+      $out/bin/systemd-boot-builder
   '';
 
   finalSystemdBootBuilder = pkgs.writeScript "install-systemd-boot.sh" ''
     #!${pkgs.runtimeShell}
-    ${checkedSystemdBootBuilder} "$@"
+    ${checkedSystemdBootBuilder}/bin/systemd-boot-builder "$@"
     ${cfg.extraInstallCommands}
   '';
 in {
@@ -81,7 +80,11 @@ in {
 
       type = types.bool;
 
-      description = lib.mdDoc "Whether to enable the systemd-boot (formerly gummiboot) EFI boot manager";
+      description = lib.mdDoc ''
+        Whether to enable the systemd-boot (formerly gummiboot) EFI boot manager.
+        For more information about systemd-boot:
+        https://www.freedesktop.org/wiki/Software/systemd/systemd-boot/
+      '';
     };
 
     editor = mkOption {
diff --git a/nixpkgs/nixos/modules/system/boot/luksroot.nix b/nixpkgs/nixos/modules/system/boot/luksroot.nix
index 221e90b6f38f..86a3875e2c67 100644
--- a/nixpkgs/nixos/modules/system/boot/luksroot.nix
+++ b/nixpkgs/nixos/modules/system/boot/luksroot.nix
@@ -1076,7 +1076,7 @@ in
     boot.initrd.systemd = {
       contents."/etc/crypttab".source = stage1Crypttab;
 
-      extraBin.systemd-cryptsetup = "${config.boot.initrd.systemd.package}/lib/systemd/systemd-cryptsetup";
+      extraBin.systemd-cryptsetup = "${config.boot.initrd.systemd.package}/bin/systemd-cryptsetup";
 
       additionalUpstreamUnits = [
         "cryptsetup-pre.target"
@@ -1084,7 +1084,7 @@ in
         "remote-cryptsetup.target"
       ];
       storePaths = [
-        "${config.boot.initrd.systemd.package}/lib/systemd/systemd-cryptsetup"
+        "${config.boot.initrd.systemd.package}/bin/systemd-cryptsetup"
         "${config.boot.initrd.systemd.package}/lib/systemd/system-generators/systemd-cryptsetup-generator"
       ];
 
diff --git a/nixpkgs/nixos/modules/system/boot/networkd.nix b/nixpkgs/nixos/modules/system/boot/networkd.nix
index f236a4c005ad..a7399bd55e77 100644
--- a/nixpkgs/nixos/modules/system/boot/networkd.nix
+++ b/nixpkgs/nixos/modules/system/boot/networkd.nix
@@ -2989,15 +2989,9 @@ let
 
       systemd.services.systemd-networkd = {
         wantedBy = [ "initrd.target" ];
-        # These before and conflicts lines can be removed when this PR makes it into a release:
-        # https://github.com/systemd/systemd/pull/27791
-        before = ["initrd-switch-root.target"];
-        conflicts = ["initrd-switch-root.target"];
       };
       systemd.sockets.systemd-networkd = {
         wantedBy = [ "initrd.target" ];
-        before = ["initrd-switch-root.target"];
-        conflicts = ["initrd-switch-root.target"];
       };
 
       systemd.services.systemd-network-generator.wantedBy = [ "sysinit.target" ];
diff --git a/nixpkgs/nixos/modules/system/boot/resolved.nix b/nixpkgs/nixos/modules/system/boot/resolved.nix
index 538f71cc0b9a..c42c88163c56 100644
--- a/nixpkgs/nixos/modules/system/boot/resolved.nix
+++ b/nixpkgs/nixos/modules/system/boot/resolved.nix
@@ -95,6 +95,29 @@ in
       '';
     };
 
+    services.resolved.dnsovertls = mkOption {
+      default = "false";
+      example = "true";
+      type = types.enum [ "true" "opportunistic" "false" ];
+      description = lib.mdDoc ''
+        If set to
+        - `"true"`:
+            all DNS lookups will be encrypted. This requires
+            that the DNS server supports DNS-over-TLS and
+            has a valid certificate. If the hostname was specified
+            via the `address#hostname` format in {option}`services.resolved.domains`
+            then the specified hostname is used to validate its certificate.
+        - `"opportunistic"`:
+            all DNS lookups will attempt to be encrypted, but will fallback
+            to unecrypted requests if the server does not support DNS-over-TLS.
+            Note that this mode does allow for a malicious party to conduct a
+            downgrade attack by immitating the DNS server and pretending to not
+            support encryption.
+        - `"false"`:
+            all DNS lookups are done unencrypted.
+      '';
+    };
+
     services.resolved.extraConfig = mkOption {
       default = "";
       type = types.lines;
@@ -141,6 +164,7 @@ in
           "Domains=${concatStringsSep " " cfg.domains}"}
         LLMNR=${cfg.llmnr}
         DNSSEC=${cfg.dnssec}
+        DNSOverTLS=${cfg.dnsovertls}
         ${config.services.resolved.extraConfig}
       '';
 
diff --git a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
index 086e5d65da2f..59cf1a47fb7f 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
@@ -86,9 +86,14 @@ touch /etc/initrd-release
 # Function for waiting for device(s) to appear.
 waitDevice() {
     local device="$1"
-    # Split device string using ':' as a delimiter as bcachefs
-    # uses this for multi-device filesystems, i.e. /dev/sda1:/dev/sda2:/dev/sda3
-    local IFS=':'
+    # Split device string using ':' as a delimiter, bcachefs uses
+    # this for multi-device filesystems, i.e. /dev/sda1:/dev/sda2:/dev/sda3
+    local IFS
+
+    # bcachefs is the only known use for this at the moment
+    # Preferably, the 'UUID=' syntax should be enforced, but
+    # this is kept for compatibility reasons
+    if [ "$fsType" = bcachefs ]; then IFS=':'; fi
 
     # USB storage devices tend to appear with some delay.  It would be
     # great if we had a way to synchronously wait for them, but
diff --git a/nixpkgs/nixos/modules/system/boot/systemd.nix b/nixpkgs/nixos/modules/system/boot/systemd.nix
index 46c3f66f02dc..e29fa49ea23b 100644
--- a/nixpkgs/nixos/modules/system/boot/systemd.nix
+++ b/nixpkgs/nixos/modules/system/boot/systemd.nix
@@ -428,7 +428,13 @@ in
 
   config = {
 
-    warnings = concatLists (
+    warnings = let
+      mkOneNetOnlineWarn = typeStr: name: def: lib.optional
+        (lib.elem "network-online.target" def.after && !(lib.elem "network-online.target" (def.wants ++ def.requires ++ def.bindsTo)))
+        "${name}.${typeStr} is ordered after 'network-online.target' but doesn't depend on it";
+      mkNetOnlineWarns = typeStr: defs: lib.concatLists (lib.mapAttrsToList (mkOneNetOnlineWarn typeStr) defs);
+      mkMountNetOnlineWarns = typeStr: defs: lib.concatLists (map (m: mkOneNetOnlineWarn typeStr m.what m) defs);
+    in concatLists (
       mapAttrsToList
         (name: service:
           let
@@ -449,7 +455,15 @@ in
             ]
         )
         cfg.services
-    );
+    )
+    ++ (mkNetOnlineWarns "target" cfg.targets)
+    ++ (mkNetOnlineWarns "service" cfg.services)
+    ++ (mkNetOnlineWarns "socket" cfg.sockets)
+    ++ (mkNetOnlineWarns "timer" cfg.timers)
+    ++ (mkNetOnlineWarns "path" cfg.paths)
+    ++ (mkMountNetOnlineWarns "mount" cfg.mounts)
+    ++ (mkMountNetOnlineWarns "automount" cfg.automounts)
+    ++ (mkNetOnlineWarns "slice" cfg.slices);
 
     assertions = concatLists (
       mapAttrsToList
diff --git a/nixpkgs/nixos/modules/system/boot/systemd/initrd.nix b/nixpkgs/nixos/modules/system/boot/systemd/initrd.nix
index 4ae07944afc3..9641921fc795 100644
--- a/nixpkgs/nixos/modules/system/boot/systemd/initrd.nix
+++ b/nixpkgs/nixos/modules/system/boot/systemd/initrd.nix
@@ -57,6 +57,7 @@ let
     "systemd-ask-password-console.service"
     "systemd-fsck@.service"
     "systemd-halt.service"
+    "systemd-hibernate-resume.service"
     "systemd-journald-audit.socket"
     "systemd-journald-dev-log.socket"
     "systemd-journald.service"
@@ -70,6 +71,7 @@ let
     "systemd-tmpfiles-setup.service"
     "timers.target"
     "umount.target"
+    "systemd-bsod.service"
   ] ++ cfg.additionalUpstreamUnits;
 
   upstreamWants = [
@@ -424,6 +426,7 @@ in {
 
       storePaths = [
         # systemd tooling
+        "${cfg.package}/lib/systemd/systemd-executor"
         "${cfg.package}/lib/systemd/systemd-fsck"
         "${cfg.package}/lib/systemd/systemd-hibernate-resume"
         "${cfg.package}/lib/systemd/systemd-journald"
@@ -433,6 +436,7 @@ in {
         "${cfg.package}/lib/systemd/systemd-shutdown"
         "${cfg.package}/lib/systemd/systemd-sulogin-shell"
         "${cfg.package}/lib/systemd/systemd-sysctl"
+        "${cfg.package}/lib/systemd/systemd-bsod"
 
         # generators
         "${cfg.package}/lib/systemd/system-generators/systemd-debug-generator"
diff --git a/nixpkgs/nixos/modules/system/boot/systemd/journald.nix b/nixpkgs/nixos/modules/system/boot/systemd/journald.nix
index 9a8e7d592603..62e24a305dde 100644
--- a/nixpkgs/nixos/modules/system/boot/systemd/journald.nix
+++ b/nixpkgs/nixos/modules/system/boot/systemd/journald.nix
@@ -56,7 +56,9 @@ in {
         journald.conf(5)](https://www.freedesktop.org/software/systemd/man/journald.conf.html).
 
         Note that the total amount of logs stored is limited by journald settings
-        such as `SystemMaxUse`, which defaults to a 4 GB cap.
+        such as `SystemMaxUse`, which defaults to 10% the file system size
+        (capped at max 4GB), and `SystemKeepFree`, which defaults to 15% of the
+        file system size.
 
         It is thus recommended to compute what period of time that you will be
         able to store logs for when an application logs at full burst rate.
diff --git a/nixpkgs/nixos/modules/system/boot/systemd/sysupdate.nix b/nixpkgs/nixos/modules/system/boot/systemd/sysupdate.nix
index cab35ddf270c..1f4088ddf825 100644
--- a/nixpkgs/nixos/modules/system/boot/systemd/sysupdate.nix
+++ b/nixpkgs/nixos/modules/system/boot/systemd/sysupdate.nix
@@ -3,7 +3,7 @@
 let
   cfg = config.systemd.sysupdate;
 
-  format = pkgs.formats.ini { };
+  format = pkgs.formats.ini { listToValue = toString; };
 
   definitionsDirectory = utils.systemdUtils.lib.definitions
     "sysupdate.d"
@@ -79,7 +79,7 @@ in
           Source = {
             Type = "url-file";
             Path = "https://download.example.com/";
-            MatchPattern = "nixos_@v.efi.xz";
+            MatchPattern = [ "nixos_@v+@l-@d.efi" "nixos_@v+@l.efi" "nixos_@v.efi" ];
           };
 
           Target = {
diff --git a/nixpkgs/nixos/modules/system/boot/systemd/sysusers.nix b/nixpkgs/nixos/modules/system/boot/systemd/sysusers.nix
new file mode 100644
index 000000000000..c619c2d91eb0
--- /dev/null
+++ b/nixpkgs/nixos/modules/system/boot/systemd/sysusers.nix
@@ -0,0 +1,169 @@
+{ config, lib, pkgs, utils, ... }:
+
+let
+
+  cfg = config.systemd.sysusers;
+  userCfg = config.users;
+
+  sysusersConfig = pkgs.writeTextDir "00-nixos.conf" ''
+    # Type Name ID GECOS Home directory Shell
+
+    # Users
+    ${lib.concatLines (lib.mapAttrsToList
+      (username: opts:
+        let
+          uid = if opts.uid == null then "-" else toString opts.uid;
+        in
+          ''u ${username} ${uid}:${opts.group} "${opts.description}" ${opts.home} ${utils.toShellPath opts.shell}''
+      )
+      userCfg.users)
+    }
+
+    # Groups
+    ${lib.concatLines (lib.mapAttrsToList
+      (groupname: opts: ''g ${groupname} ${if opts.gid == null then "-" else toString opts.gid}'') userCfg.groups)
+    }
+
+    # Group membership
+    ${lib.concatStrings (lib.mapAttrsToList
+      (groupname: opts: (lib.concatMapStrings (username: "m ${username} ${groupname}\n")) opts.members ) userCfg.groups)
+    }
+  '';
+
+  staticSysusersCredentials = pkgs.runCommand "static-sysusers-credentials" { } ''
+    mkdir $out; cd $out
+    ${lib.concatLines (
+      (lib.mapAttrsToList
+        (username: opts: "echo -n '${opts.initialHashedPassword}' > 'passwd.hashed-password.${username}'")
+        (lib.filterAttrs (_username: opts: opts.initialHashedPassword != null) userCfg.users))
+        ++
+      (lib.mapAttrsToList
+        (username: opts: "echo -n '${opts.initialPassword}' > 'passwd.plaintext-password.${username}'")
+        (lib.filterAttrs (_username: opts: opts.initialPassword != null) userCfg.users))
+        ++
+      (lib.mapAttrsToList
+        (username: opts: "cat '${opts.hashedPasswordFile}' > 'passwd.hashed-password.${username}'")
+        (lib.filterAttrs (_username: opts: opts.hashedPasswordFile != null) userCfg.users))
+      )
+    }
+  '';
+
+  staticSysusers = pkgs.runCommand "static-sysusers"
+    {
+      nativeBuildInputs = [ pkgs.systemd ];
+    } ''
+    mkdir $out
+    export CREDENTIALS_DIRECTORY=${staticSysusersCredentials}
+    systemd-sysusers --root $out ${sysusersConfig}/00-nixos.conf
+  '';
+
+in
+
+{
+
+  options = {
+
+    # This module doesn't set it's own user options but reuses the ones from
+    # users-groups.nix
+
+    systemd.sysusers = {
+      enable = lib.mkEnableOption (lib.mdDoc "systemd-sysusers") // {
+        description = lib.mdDoc ''
+          If enabled, users are created with systemd-sysusers instead of with
+          the custom `update-users-groups.pl` script.
+
+          Note: This is experimental.
+        '';
+      };
+    };
+
+  };
+
+  config = lib.mkIf cfg.enable {
+
+    assertions = [
+      {
+        assertion = config.system.activationScripts.users == "";
+        message = "system.activationScripts.users has to be empty to use systemd-sysusers";
+      }
+      {
+        assertion = config.users.mutableUsers -> config.system.etc.overlay.enable;
+        message = "config.users.mutableUsers requires config.system.etc.overlay.enable.";
+      }
+    ];
+
+    systemd = lib.mkMerge [
+      ({
+
+        # Create home directories, do not create /var/empty even if that's a user's
+        # home.
+        tmpfiles.settings.home-directories = lib.mapAttrs'
+          (username: opts: lib.nameValuePair opts.home {
+            d = {
+              mode = opts.homeMode;
+              user = username;
+              group = opts.group;
+            };
+          })
+          (lib.filterAttrs (_username: opts: opts.home != "/var/empty") userCfg.users);
+      })
+
+      (lib.mkIf config.users.mutableUsers {
+        additionalUpstreamSystemUnits = [
+          "systemd-sysusers.service"
+        ];
+
+        services.systemd-sysusers = {
+          # Enable switch-to-configuration to restart the service.
+          unitConfig.ConditionNeedsUpdate = [ "" ];
+          requiredBy = [ "sysinit-reactivation.target" ];
+          before = [ "sysinit-reactivation.target" ];
+          restartTriggers = [ "${config.environment.etc."sysusers.d".source}" ];
+
+          serviceConfig = {
+            LoadCredential = lib.mapAttrsToList
+              (username: opts: "passwd.hashed-password.${username}:${opts.hashedPasswordFile}")
+              (lib.filterAttrs (_username: opts: opts.hashedPasswordFile != null) userCfg.users);
+            SetCredential = (lib.mapAttrsToList
+              (username: opts: "passwd.hashed-password.${username}:${opts.initialHashedPassword}")
+              (lib.filterAttrs (_username: opts: opts.initialHashedPassword != null) userCfg.users))
+            ++
+            (lib.mapAttrsToList
+              (username: opts: "passwd.plaintext-password.${username}:${opts.initialPassword}")
+              (lib.filterAttrs (_username: opts: opts.initialPassword != null) userCfg.users))
+            ;
+          };
+        };
+      })
+    ];
+
+    environment.etc = lib.mkMerge [
+      (lib.mkIf (!userCfg.mutableUsers) {
+        "passwd" = {
+          source = "${staticSysusers}/etc/passwd";
+          mode = "0644";
+        };
+        "group" = {
+          source = "${staticSysusers}/etc/group";
+          mode = "0644";
+        };
+        "shadow" = {
+          source = "${staticSysusers}/etc/shadow";
+          mode = "0000";
+        };
+        "gshadow" = {
+          source = "${staticSysusers}/etc/gshadow";
+          mode = "0000";
+        };
+      })
+
+      (lib.mkIf userCfg.mutableUsers {
+        "sysusers.d".source = sysusersConfig;
+      })
+    ];
+
+  };
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+}
diff --git a/nixpkgs/nixos/modules/system/boot/uki.nix b/nixpkgs/nixos/modules/system/boot/uki.nix
new file mode 100644
index 000000000000..63a7cbc5967b
--- /dev/null
+++ b/nixpkgs/nixos/modules/system/boot/uki.nix
@@ -0,0 +1,85 @@
+{ config, lib, pkgs, ... }:
+
+let
+
+  cfg = config.boot.uki;
+
+  inherit (pkgs.stdenv.hostPlatform) efiArch;
+
+  format = pkgs.formats.ini { };
+  ukifyConfig = format.generate "ukify.conf" cfg.settings;
+
+in
+
+{
+  options = {
+
+    boot.uki = {
+      name = lib.mkOption {
+        type = lib.types.str;
+        description = lib.mdDoc "Name of the UKI";
+      };
+
+      version = lib.mkOption {
+        type = lib.types.nullOr lib.types.str;
+        default = config.system.image.version;
+        defaultText = lib.literalExpression "config.system.image.version";
+        description = lib.mdDoc "Version of the image or generation the UKI belongs to";
+      };
+
+      settings = lib.mkOption {
+        type = format.type;
+        description = lib.mdDoc ''
+          The configuration settings for ukify. These control what the UKI
+          contains and how it is built.
+        '';
+      };
+    };
+
+    system.boot.loader.ukiFile = lib.mkOption {
+      type = lib.types.str;
+      internal = true;
+      description = lib.mdDoc "Name of the UKI file";
+    };
+
+  };
+
+  config = {
+
+    boot.uki.name = lib.mkOptionDefault (if config.system.image.id != null then
+      config.system.image.id
+    else
+      "nixos");
+
+    boot.uki.settings = {
+      UKI = {
+        Linux = lib.mkOptionDefault "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
+        Initrd = lib.mkOptionDefault "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
+        Cmdline = lib.mkOptionDefault "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}";
+        Stub = lib.mkOptionDefault "${pkgs.systemd}/lib/systemd/boot/efi/linux${efiArch}.efi.stub";
+        Uname = lib.mkOptionDefault "${config.boot.kernelPackages.kernel.modDirVersion}";
+        OSRelease = lib.mkOptionDefault "@${config.system.build.etc}/etc/os-release";
+        # This is needed for cross compiling.
+        EFIArch = lib.mkOptionDefault efiArch;
+      };
+    };
+
+    system.boot.loader.ukiFile =
+      let
+        name = config.boot.uki.name;
+        version = config.boot.uki.version;
+        versionInfix = if version != null then "_${version}" else "";
+      in
+      name + versionInfix + ".efi";
+
+    system.build.uki = pkgs.runCommand config.system.boot.loader.ukiFile { } ''
+      mkdir -p $out
+      ${pkgs.buildPackages.systemdUkify}/lib/systemd/ukify build \
+        --config=${ukifyConfig} \
+        --output="$out/${config.system.boot.loader.ukiFile}"
+    '';
+
+    meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/system/etc/build-composefs-dump.py b/nixpkgs/nixos/modules/system/etc/build-composefs-dump.py
new file mode 100644
index 000000000000..bf4ec791ecf7
--- /dev/null
+++ b/nixpkgs/nixos/modules/system/etc/build-composefs-dump.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python3
+
+"""Build a composefs dump from a Json config
+
+See the man page of composefs-dump for details about the format:
+https://github.com/containers/composefs/blob/main/man/composefs-dump.md
+
+Ensure to check the file with the check script when you make changes to it:
+
+./check-build-composefs-dump.sh ./build-composefs_dump.py
+"""
+
+import glob
+import json
+import os
+import sys
+from enum import Enum
+from pathlib import Path
+from typing import Any
+
+Attrs = dict[str, Any]
+
+
+class FileType(Enum):
+    """The filetype as defined by the `st_mode` stat field in octal
+
+    You can check the st_mode stat field of a path in Python with
+    `oct(os.stat("/path/").st_mode)`
+    """
+
+    directory = "4"
+    file = "10"
+    symlink = "12"
+
+
+class ComposefsPath:
+    path: str
+    size: int
+    filetype: FileType
+    mode: str
+    uid: str
+    gid: str
+    payload: str
+    rdev: str = "0"
+    nlink: int = 1
+    mtime: str = "1.0"
+    content: str = "-"
+    digest: str = "-"
+
+    def __init__(
+        self,
+        attrs: Attrs,
+        size: int,
+        filetype: FileType,
+        mode: str,
+        payload: str,
+        path: str | None = None,
+    ):
+        if path is None:
+            path = attrs["target"]
+        self.path = path
+        self.size = size
+        self.filetype = filetype
+        self.mode = mode
+        self.uid = attrs["uid"]
+        self.gid = attrs["gid"]
+        self.payload = payload
+
+    def write_line(self) -> str:
+        line_list = [
+            str(self.path),
+            str(self.size),
+            f"{self.filetype.value}{self.mode}",
+            str(self.nlink),
+            str(self.uid),
+            str(self.gid),
+            str(self.rdev),
+            str(self.mtime),
+            str(self.payload),
+            str(self.content),
+            str(self.digest),
+        ]
+        return " ".join(line_list)
+
+
+def eprint(*args: Any, **kwargs: Any) -> None:
+    print(*args, **kwargs, file=sys.stderr)
+
+
+def normalize_path(path: str) -> str:
+    return str("/" + os.path.normpath(path).lstrip("/"))
+
+
+def leading_directories(path: str) -> list[str]:
+    """Return the leading directories of path
+
+    Given the path "alsa/conf.d/50-pipewire.conf", for example, this function
+    returns `[ "alsa", "alsa/conf.d" ]`.
+    """
+    parents = list(Path(path).parents)
+    parents.reverse()
+    # remove the implicit `.` from the start of a relative path or `/` from an
+    # absolute path
+    del parents[0]
+    return [str(i) for i in parents]
+
+
+def add_leading_directories(
+    target: str, attrs: Attrs, paths: dict[str, ComposefsPath]
+) -> None:
+    """Add the leading directories of a target path to the composefs paths
+
+    mkcomposefs expects that all leading directories are explicitly listed in
+    the dump file. Given the path "alsa/conf.d/50-pipewire.conf", for example,
+    this function adds "alsa" and "alsa/conf.d" to the composefs paths.
+    """
+    path_components = leading_directories(target)
+    for component in path_components:
+        composefs_path = ComposefsPath(
+            attrs,
+            path=component,
+            size=4096,
+            filetype=FileType.directory,
+            mode="0755",
+            payload="-",
+        )
+        paths[component] = composefs_path
+
+
+def main() -> None:
+    """Build a composefs dump from a Json config
+
+    This config describes the files that the final composefs image is supposed
+    to contain.
+    """
+    config_file = sys.argv[1]
+    if not config_file:
+        eprint("No config file was supplied.")
+        sys.exit(1)
+
+    with open(config_file, "rb") as f:
+        config = json.load(f)
+
+    if not config:
+        eprint("Config is empty.")
+        sys.exit(1)
+
+    eprint("Building composefs dump...")
+
+    paths: dict[str, ComposefsPath] = {}
+    for attrs in config:
+        # Normalize the target path to work around issues in how targets are
+        # declared in `environment.etc`.
+        attrs["target"] = normalize_path(attrs["target"])
+
+        target = attrs["target"]
+        source = attrs["source"]
+        mode = attrs["mode"]
+
+        if "*" in source:  # Path with globbing
+            glob_sources = glob.glob(source)
+            for glob_source in glob_sources:
+                basename = os.path.basename(glob_source)
+                glob_target = f"{target}/{basename}"
+
+                composefs_path = ComposefsPath(
+                    attrs,
+                    path=glob_target,
+                    size=100,
+                    filetype=FileType.symlink,
+                    mode="0777",
+                    payload=glob_source,
+                )
+
+                paths[glob_target] = composefs_path
+                add_leading_directories(glob_target, attrs, paths)
+        else:  # Without globbing
+            if mode == "symlink":
+                composefs_path = ComposefsPath(
+                    attrs,
+                    # A high approximation of the size of a symlink
+                    size=100,
+                    filetype=FileType.symlink,
+                    mode="0777",
+                    payload=source,
+                )
+            else:
+                if os.path.isdir(source):
+                    composefs_path = ComposefsPath(
+                        attrs,
+                        size=4096,
+                        filetype=FileType.directory,
+                        mode=mode,
+                        payload=source,
+                    )
+                else:
+                    composefs_path = ComposefsPath(
+                        attrs,
+                        size=os.stat(source).st_size,
+                        filetype=FileType.file,
+                        mode=mode,
+                        payload=target,
+                    )
+            paths[target] = composefs_path
+            add_leading_directories(target, attrs, paths)
+
+    composefs_dump = ["/ 4096 40755 1 0 0 0 0.0 - - -"]  # Root directory
+    for key in sorted(paths):
+        composefs_path = paths[key]
+        eprint(composefs_path.path)
+        composefs_dump.append(composefs_path.write_line())
+
+    print("\n".join(composefs_dump))
+
+
+if __name__ == "__main__":
+    main()
diff --git a/nixpkgs/nixos/modules/system/etc/check-build-composefs-dump.sh b/nixpkgs/nixos/modules/system/etc/check-build-composefs-dump.sh
new file mode 100755
index 000000000000..da61651d1a5d
--- /dev/null
+++ b/nixpkgs/nixos/modules/system/etc/check-build-composefs-dump.sh
@@ -0,0 +1,8 @@
+#! /usr/bin/env nix-shell
+#! nix-shell -i bash -p black ruff mypy
+
+file=$1
+
+black --check --diff $file
+ruff --line-length 88 $file
+mypy --strict $file
diff --git a/nixpkgs/nixos/modules/system/etc/etc-activation.nix b/nixpkgs/nixos/modules/system/etc/etc-activation.nix
index 780104950186..f47fd771c659 100644
--- a/nixpkgs/nixos/modules/system/etc/etc-activation.nix
+++ b/nixpkgs/nixos/modules/system/etc/etc-activation.nix
@@ -1,12 +1,96 @@
 { config, lib, ... }:
-let
-  inherit (lib) stringAfter;
-in {
+
+{
 
   imports = [ ./etc.nix ];
 
-  config = {
-    system.activationScripts.etc =
-      stringAfter [ "users" "groups" ] config.system.build.etcActivationCommands;
-  };
+  config = lib.mkMerge [
+
+    {
+      system.activationScripts.etc =
+        lib.stringAfter [ "users" "groups" ] config.system.build.etcActivationCommands;
+    }
+
+    (lib.mkIf config.system.etc.overlay.enable {
+
+      assertions = [
+        {
+          assertion = config.boot.initrd.systemd.enable;
+          message = "`system.etc.overlay.enable` requires `boot.initrd.systemd.enable`";
+        }
+        {
+          assertion = (!config.system.etc.overlay.mutable) -> config.systemd.sysusers.enable;
+          message = "`system.etc.overlay.mutable = false` requires `systemd.sysusers.enable`";
+        }
+        {
+          assertion = lib.versionAtLeast config.boot.kernelPackages.kernel.version "6.6";
+          message = "`system.etc.overlay.enable requires a newer kernel, at least version 6.6";
+        }
+        {
+          assertion = config.systemd.sysusers.enable -> (config.users.mutableUsers == config.system.etc.overlay.mutable);
+          message = ''
+            When using systemd-sysusers and mounting `/etc` via an overlay, users
+            can only be mutable when `/etc` is mutable and vice versa.
+          '';
+        }
+      ];
+
+      boot.initrd.availableKernelModules = [ "loop" "erofs" "overlay" ];
+
+      boot.initrd.systemd = {
+        mounts = [
+          {
+            where = "/run/etc-metadata";
+            what = "/sysroot${config.system.build.etcMetadataImage}";
+            type = "erofs";
+            options = "loop";
+            unitConfig.RequiresMountsFor = [
+              "/sysroot/nix/store"
+            ];
+          }
+          {
+            where = "/sysroot/etc";
+            what = "overlay";
+            type = "overlay";
+            options = lib.concatStringsSep "," ([
+              "relatime"
+              "redirect_dir=on"
+              "metacopy=on"
+              "lowerdir=/run/etc-metadata::/sysroot${config.system.build.etcBasedir}"
+            ] ++ lib.optionals config.system.etc.overlay.mutable [
+              "rw"
+              "upperdir=/sysroot/.rw-etc/upper"
+              "workdir=/sysroot/.rw-etc/work"
+            ] ++ lib.optionals (!config.system.etc.overlay.mutable) [
+              "ro"
+            ]);
+            wantedBy = [ "initrd-fs.target" ];
+            before = [ "initrd-fs.target" ];
+            requires = lib.mkIf config.system.etc.overlay.mutable [ "rw-etc.service" ];
+            after = lib.mkIf config.system.etc.overlay.mutable [ "rw-etc.service" ];
+            unitConfig.RequiresMountsFor = [
+              "/sysroot/nix/store"
+              "/run/etc-metadata"
+            ];
+          }
+        ];
+        services = lib.mkIf config.system.etc.overlay.mutable {
+          rw-etc = {
+            unitConfig = {
+              DefaultDependencies = false;
+              RequiresMountsFor = "/sysroot";
+            };
+            serviceConfig = {
+              Type = "oneshot";
+              ExecStart = ''
+                /bin/mkdir -p -m 0755 /sysroot/.rw-etc/upper /sysroot/.rw-etc/work
+              '';
+            };
+          };
+        };
+      };
+
+    })
+
+  ];
 }
diff --git a/nixpkgs/nixos/modules/system/etc/etc.nix b/nixpkgs/nixos/modules/system/etc/etc.nix
index ea61e7384e60..baf37ba6def3 100644
--- a/nixpkgs/nixos/modules/system/etc/etc.nix
+++ b/nixpkgs/nixos/modules/system/etc/etc.nix
@@ -62,6 +62,16 @@ let
     ]) etc'}
   '';
 
+  etcHardlinks = filter (f: f.mode != "symlink") etc';
+
+  build-composefs-dump = pkgs.runCommand "build-composefs-dump.py"
+    {
+      buildInputs = [ pkgs.python3 ];
+    } ''
+    install ${./build-composefs-dump.py} $out
+    patchShebangs --host $out
+  '';
+
 in
 
 {
@@ -72,6 +82,30 @@ in
 
   options = {
 
+    system.etc.overlay = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Mount `/etc` as an overlayfs instead of generating it via a perl script.
+
+          Note: This is currently experimental. Only enable this option if you're
+          confident that you can recover your system if it breaks.
+        '';
+      };
+
+      mutable = mkOption {
+        type = types.bool;
+        default = true;
+        description = lib.mdDoc ''
+          Whether to mount `/etc` mutably (i.e. read-write) or immutably (i.e. read-only).
+
+          If this is false, only the immutable lowerdir is mounted. If it is
+          true, a writable upperdir is mounted on top.
+        '';
+      };
+    };
+
     environment.etc = mkOption {
       default = {};
       example = literalExpression ''
@@ -190,12 +224,84 @@ in
   config = {
 
     system.build.etc = etc;
-    system.build.etcActivationCommands =
-      ''
-        # Set up the statically computed bits of /etc.
-        echo "setting up /etc..."
-        ${pkgs.perl.withPackages (p: [ p.FileSlurp ])}/bin/perl ${./setup-etc.pl} ${etc}/etc
+    system.build.etcActivationCommands = let
+      etcOverlayOptions = lib.concatStringsSep "," ([
+        "relatime"
+        "redirect_dir=on"
+        "metacopy=on"
+      ] ++ lib.optionals config.system.etc.overlay.mutable [
+        "upperdir=/.rw-etc/upper"
+        "workdir=/.rw-etc/work"
+      ]);
+    in if config.system.etc.overlay.enable then ''
+      # This script atomically remounts /etc when switching configuration. On a (re-)boot
+      # this should not run because /etc is mounted via a systemd mount unit
+      # instead. To a large extent this mimics what composefs does. Because
+      # it's relatively simple, however, we avoid the composefs dependency.
+      if [[ ! $IN_NIXOS_SYSTEMD_STAGE1 ]]; then
+        echo "remounting /etc..."
+
+        tmpMetadataMount=$(mktemp --directory)
+        mount --type erofs ${config.system.build.etcMetadataImage} $tmpMetadataMount
+
+        # Mount the new /etc overlay to a temporary private mount.
+        # This needs the indirection via a private bind mount because you
+        # cannot move shared mounts.
+        tmpEtcMount=$(mktemp --directory)
+        mount --bind --make-private $tmpEtcMount $tmpEtcMount
+        mount --type overlay overlay \
+          --options lowerdir=$tmpMetadataMount::${config.system.build.etcBasedir},${etcOverlayOptions} \
+          $tmpEtcMount
+
+        # Move the new temporary /etc mount underneath the current /etc mount.
+        #
+        # This should eventually use util-linux to perform this move beneath,
+        # however, this functionality is not yet in util-linux. See this
+        # tracking issue: https://github.com/util-linux/util-linux/issues/2604
+        ${pkgs.move-mount-beneath}/bin/move-mount --move --beneath $tmpEtcMount /etc
+
+        # Unmount the top /etc mount to atomically reveal the new mount.
+        umount /etc
+
+      fi
+    '' else ''
+      # Set up the statically computed bits of /etc.
+      echo "setting up /etc..."
+      ${pkgs.perl.withPackages (p: [ p.FileSlurp ])}/bin/perl ${./setup-etc.pl} ${etc}/etc
+    '';
+
+    system.build.etcBasedir = pkgs.runCommandLocal "etc-lowerdir" { } ''
+      set -euo pipefail
+
+      makeEtcEntry() {
+        src="$1"
+        target="$2"
+
+        mkdir -p "$out/$(dirname "$target")"
+        cp "$src" "$out/$target"
+      }
+
+      mkdir -p "$out"
+      ${concatMapStringsSep "\n" (etcEntry: escapeShellArgs [
+        "makeEtcEntry"
+        # Force local source paths to be added to the store
+        "${etcEntry.source}"
+        etcEntry.target
+      ]) etcHardlinks}
+    '';
+
+    system.build.etcMetadataImage =
+      let
+        etcJson = pkgs.writeText "etc-json" (builtins.toJSON etc');
+        etcDump = pkgs.runCommand "etc-dump" { } "${build-composefs-dump} ${etcJson} > $out";
+      in
+      pkgs.runCommand "etc-metadata.erofs" {
+        nativeBuildInputs = [ pkgs.composefs pkgs.erofs-utils ];
+      } ''
+        mkcomposefs --from-file ${etcDump} $out
+        fsck.erofs $out
       '';
+
   };
 
 }
diff --git a/nixpkgs/nixos/modules/tasks/auto-upgrade.nix b/nixpkgs/nixos/modules/tasks/auto-upgrade.nix
index 29e3e313336f..22311871274b 100644
--- a/nixpkgs/nixos/modules/tasks/auto-upgrade.nix
+++ b/nixpkgs/nixos/modules/tasks/auto-upgrade.nix
@@ -109,6 +109,17 @@ in {
         '';
       };
 
+      fixedRandomDelay = mkOption {
+        default = false;
+        type = types.bool;
+        example = true;
+        description = lib.mdDoc ''
+          Make the randomized delay consistent between runs.
+          This reduces the jitter between automatic upgrades.
+          See {option}`randomizedDelaySec` for configuring the randomized delay.
+        '';
+      };
+
       rebootWindow = mkOption {
         description = lib.mdDoc ''
           Define a lower and upper time value (in HH:MM format) which
@@ -253,6 +264,7 @@ in {
     systemd.timers.nixos-upgrade = {
       timerConfig = {
         RandomizedDelaySec = cfg.randomizedDelaySec;
+        FixedRandomDelay = cfg.fixedRandomDelay;
         Persistent = cfg.persistent;
       };
     };
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix b/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix
index fdb149a3d9a1..3b990ce30b21 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/bcachefs.nix
@@ -123,9 +123,14 @@ in
       inherit assertions;
       # needed for systemd-remount-fs
       system.fsPackages = [ pkgs.bcachefs-tools ];
-      # FIXME: Remove this line when the default kernel has bcachefs
+      # FIXME: Remove this line when the LTS (default) kernel is at least version 6.7
       boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
-      systemd.services = lib.mapAttrs' (mkUnits "") (lib.filterAttrs (n: fs: (fs.fsType == "bcachefs") && (!utils.fsNeededForBoot fs)) config.fileSystems);
+      services.udev.packages = [ pkgs.bcachefs-tools ];
+
+      systemd = {
+        packages = [ pkgs.bcachefs-tools ];
+        services = lib.mapAttrs' (mkUnits "") (lib.filterAttrs (n: fs: (fs.fsType == "bcachefs") && (!utils.fsNeededForBoot fs)) config.fileSystems);
+      };
     }
 
     (lib.mkIf ((lib.elem "bcachefs" config.boot.initrd.supportedFilesystems) || (bootFs != {})) {
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/overlayfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/overlayfs.nix
new file mode 100644
index 000000000000..e71ef9ba62e9
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/overlayfs.nix
@@ -0,0 +1,144 @@
+{ config, lib, pkgs, utils, ... }:
+
+let
+  # The scripted initrd contains some magic to add the prefix to the
+  # paths just in time, so we don't add it here.
+  sysrootPrefix = fs:
+    if config.boot.initrd.systemd.enable && (utils.fsNeededForBoot fs) then
+      "/sysroot"
+    else
+      "";
+
+  # Returns a service that creates the required directories before the mount is
+  # created.
+  preMountService = _name: fs:
+    let
+      prefix = sysrootPrefix fs;
+
+      escapedMountpoint = utils.escapeSystemdPath (prefix + fs.mountPoint);
+      mountUnit = "${escapedMountpoint}.mount";
+
+      upperdir = prefix + fs.overlay.upperdir;
+      workdir = prefix + fs.overlay.workdir;
+    in
+    lib.mkIf (fs.overlay.upperdir != null)
+      {
+        "rw-${escapedMountpoint}" = {
+          requiredBy = [ mountUnit ];
+          before = [ mountUnit ];
+          unitConfig = {
+            DefaultDependencies = false;
+            RequiresMountsFor = "${upperdir} ${workdir}";
+          };
+          serviceConfig = {
+            Type = "oneshot";
+            ExecStart = "${pkgs.coreutils}/bin/mkdir -p -m 0755 ${upperdir} ${workdir}";
+          };
+        };
+      };
+
+  overlayOpts = { config, ... }: {
+
+    options.overlay = {
+
+      lowerdir = lib.mkOption {
+        type = with lib.types; nullOr (nonEmptyListOf (either str pathInStore));
+        default = null;
+        description = lib.mdDoc ''
+          The list of path(s) to the lowerdir(s).
+
+          To create a writable overlay, you MUST provide an upperdir and a
+          workdir.
+
+          You can create a read-only overlay when you provide multiple (at
+          least 2!) lowerdirs and neither an upperdir nor a workdir.
+        '';
+      };
+
+      upperdir = lib.mkOption {
+        type = lib.types.nullOr lib.types.str;
+        default = null;
+        description = lib.mdDoc ''
+          The path to the upperdir.
+
+          If this is null, a read-only overlay is created using the lowerdir.
+
+          If you set this to some value you MUST also set `workdir`.
+        '';
+      };
+
+      workdir = lib.mkOption {
+        type = lib.types.nullOr lib.types.str;
+        default = null;
+        description = lib.mdDoc ''
+          The path to the workdir.
+
+          This MUST be set if you set `upperdir`.
+        '';
+      };
+
+    };
+
+    config = lib.mkIf (config.overlay.lowerdir != null) {
+      fsType = "overlay";
+      device = lib.mkDefault "overlay";
+
+      options =
+        let
+          prefix = sysrootPrefix config;
+
+          lowerdir = map (s: prefix + s) config.overlay.lowerdir;
+          upperdir = prefix + config.overlay.upperdir;
+          workdir = prefix + config.overlay.workdir;
+        in
+        [
+          "lowerdir=${lib.concatStringsSep ":" lowerdir}"
+        ] ++ lib.optionals (config.overlay.upperdir != null) [
+          "upperdir=${upperdir}"
+          "workdir=${workdir}"
+        ] ++ (map (s: "x-systemd.requires-mounts-for=${s}") lowerdir);
+    };
+
+  };
+in
+
+{
+
+  options = {
+
+    # Merge the overlay options into the fileSystems option.
+    fileSystems = lib.mkOption {
+      type = lib.types.attrsOf (lib.types.submodule [ overlayOpts ]);
+    };
+
+  };
+
+  config =
+    let
+      overlayFileSystems = lib.filterAttrs (_name: fs: (fs.overlay.lowerdir != null)) config.fileSystems;
+      initrdFileSystems = lib.filterAttrs (_name: utils.fsNeededForBoot) overlayFileSystems;
+      userspaceFileSystems = lib.filterAttrs (_name: fs: (!utils.fsNeededForBoot fs)) overlayFileSystems;
+    in
+    {
+
+      boot.initrd.availableKernelModules = lib.mkIf (initrdFileSystems != { }) [ "overlay" ];
+
+      assertions = lib.concatLists (lib.mapAttrsToList
+        (_name: fs: [
+          {
+            assertion = (fs.overlay.upperdir == null) == (fs.overlay.workdir == null);
+            message = "You cannot define a `lowerdir` without a `workdir` and vice versa for mount point: ${fs.mountPoint}";
+          }
+          {
+            assertion = (fs.overlay.lowerdir != null && fs.overlay.upperdir == null) -> (lib.length fs.overlay.lowerdir) >= 2;
+            message = "A read-only overlay (without an `upperdir`) requires at least 2 `lowerdir`s: ${fs.mountPoint}";
+          }
+        ])
+        config.fileSystems);
+
+      boot.initrd.systemd.services = lib.mkMerge (lib.mapAttrsToList preMountService initrdFileSystems);
+      systemd.services = lib.mkMerge (lib.mapAttrsToList preMountService userspaceFileSystems);
+
+    };
+
+}
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/sshfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/sshfs.nix
new file mode 100644
index 000000000000..cd71dda16d8b
--- /dev/null
+++ b/nixpkgs/nixos/modules/tasks/filesystems/sshfs.nix
@@ -0,0 +1,7 @@
+{ config, lib, pkgs, ... }:
+
+{
+  config = lib.mkIf (lib.any (fs: fs == "sshfs" || fs == "fuse.sshfs") config.boot.supportedFilesystems) {
+    system.fsPackages = [ pkgs.sshfs ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/testing/test-instrumentation.nix b/nixpkgs/nixos/modules/testing/test-instrumentation.nix
index 9ee77cd79a9b..6aa718c1975d 100644
--- a/nixpkgs/nixos/modules/testing/test-instrumentation.nix
+++ b/nixpkgs/nixos/modules/testing/test-instrumentation.nix
@@ -207,7 +207,10 @@ in
     networking.usePredictableInterfaceNames = false;
 
     # Make it easy to log in as root when running the test interactively.
-    users.users.root.initialHashedPassword = mkOverride 150 "";
+    # This needs to be a file because of a quirk in systemd credentials,
+    # where you cannot specify an empty string as a value. systemd-sysusers
+    # uses credentials to set passwords on users.
+    users.users.root.hashedPasswordFile = mkOverride 150 "${pkgs.writeText "hashed-password.root" ""}";
 
     services.xserver.displayManager.job.logToJournal = true;
 
diff --git a/nixpkgs/nixos/modules/virtualisation/amazon-image.nix b/nixpkgs/nixos/modules/virtualisation/amazon-image.nix
index aa44f2642697..c7fe1bed5159 100644
--- a/nixpkgs/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixpkgs/nixos/modules/virtualisation/amazon-image.nix
@@ -71,6 +71,7 @@ in
 
     systemd.services.fetch-ec2-metadata = {
       wantedBy = [ "multi-user.target" ];
+      wants = [ "network-online.target" ];
       after = ["network-online.target"];
       path = [ pkgs.curl ];
       script = builtins.readFile ./ec2-metadata-fetcher.sh;
@@ -102,4 +103,5 @@ in
     # (e.g. it depends on GTK).
     services.udisks2.enable = false;
   };
+  meta.maintainers = with maintainers; [ arianvp ];
 }
diff --git a/nixpkgs/nixos/modules/virtualisation/amazon-init.nix b/nixpkgs/nixos/modules/virtualisation/amazon-init.nix
index 8b98f2e32dd5..8475097df07c 100644
--- a/nixpkgs/nixos/modules/virtualisation/amazon-init.nix
+++ b/nixpkgs/nixos/modules/virtualisation/amazon-init.nix
@@ -84,4 +84,5 @@ in {
       };
     };
   };
+  meta.maintainers = with maintainers; [ arianvp ];
 }
diff --git a/nixpkgs/nixos/modules/virtualisation/incus.nix b/nixpkgs/nixos/modules/virtualisation/incus.nix
index ea4cb916aa08..bbe5b48b95bb 100644
--- a/nixpkgs/nixos/modules/virtualisation/incus.nix
+++ b/nixpkgs/nixos/modules/virtualisation/incus.nix
@@ -160,7 +160,10 @@ in
         "network-online.target"
       ];
 
-      path = lib.mkIf config.boot.zfs.enabled [ config.boot.zfs.package ];
+      path = lib.mkIf config.boot.zfs.enabled [
+        config.boot.zfs.package
+        "${config.boot.zfs.package}/lib/udev"
+      ];
 
       environment = {
         # Override Path to the LXC template configuration directory
diff --git a/nixpkgs/nixos/modules/virtualisation/libvirtd.nix b/nixpkgs/nixos/modules/virtualisation/libvirtd.nix
index 217242a8fbd2..b8f952d3ba0e 100644
--- a/nixpkgs/nixos/modules/virtualisation/libvirtd.nix
+++ b/nixpkgs/nixos/modules/virtualisation/libvirtd.nix
@@ -466,6 +466,7 @@ in
         Type = "notify";
         KillMode = "process"; # when stopping, leave the VMs alone
         Restart = "no";
+        OOMScoreAdjust = "-999";
       };
       restartIfChanged = false;
     };
diff --git a/nixpkgs/nixos/modules/virtualisation/oci-containers.nix b/nixpkgs/nixos/modules/virtualisation/oci-containers.nix
index a4a40346f093..b6a7b1154c4a 100644
--- a/nixpkgs/nixos/modules/virtualisation/oci-containers.nix
+++ b/nixpkgs/nixos/modules/virtualisation/oci-containers.nix
@@ -267,6 +267,7 @@ let
     };
   in {
     wantedBy = [] ++ optional (container.autoStart) "multi-user.target";
+    wants = lib.optional (container.imageFile == null)  "network-online.target";
     after = lib.optionals (cfg.backend == "docker") [ "docker.service" "docker.socket" ]
             # if imageFile is not set, the service needs the network to download the image from the registry
             ++ lib.optionals (container.imageFile == null) [ "network-online.target" ]
@@ -307,9 +308,10 @@ let
     );
 
     preStop = if cfg.backend == "podman"
-      then "[ $SERVICE_RESULT = success ] || podman stop --ignore --cidfile=/run/podman-${escapedName}.ctr-id"
-      else "[ $SERVICE_RESULT = success ] || ${cfg.backend} stop ${name}";
-    postStop =  if cfg.backend == "podman"
+      then "podman stop --ignore --cidfile=/run/podman-${escapedName}.ctr-id"
+      else "${cfg.backend} stop ${name}";
+
+    postStop = if cfg.backend == "podman"
       then "podman rm -f --ignore --cidfile=/run/podman-${escapedName}.ctr-id"
       else "${cfg.backend} rm -f ${name} || true";
 
diff --git a/nixpkgs/nixos/modules/virtualisation/podman/default.nix b/nixpkgs/nixos/modules/virtualisation/podman/default.nix
index ec0b713e58b3..47382f9beab0 100644
--- a/nixpkgs/nixos/modules/virtualisation/podman/default.nix
+++ b/nixpkgs/nixos/modules/virtualisation/podman/default.nix
@@ -150,26 +150,33 @@ in
 
   };
 
-  config = lib.mkIf cfg.enable
-    {
+  config =
+    let
+      networkConfig = ({
+        dns_enabled = false;
+        driver = "bridge";
+        id = "0000000000000000000000000000000000000000000000000000000000000000";
+        internal = false;
+        ipam_options = { driver = "host-local"; };
+        ipv6_enabled = false;
+        name = "podman";
+        network_interface = "podman0";
+        subnets = [{ gateway = "10.88.0.1"; subnet = "10.88.0.0/16"; }];
+      } // cfg.defaultNetwork.settings);
+      inherit (networkConfig) dns_enabled network_interface;
+    in
+    lib.mkIf cfg.enable {
       environment.systemPackages = [ cfg.package ]
         ++ lib.optional cfg.dockerCompat dockerCompat;
 
       # https://github.com/containers/podman/blob/097cc6eb6dd8e598c0e8676d21267b4edb11e144/docs/tutorials/basic_networking.md#default-network
       environment.etc."containers/networks/podman.json" = lib.mkIf (cfg.defaultNetwork.settings != { }) {
-        source = json.generate "podman.json" ({
-          dns_enabled = false;
-          driver = "bridge";
-          id = "0000000000000000000000000000000000000000000000000000000000000000";
-          internal = false;
-          ipam_options = { driver = "host-local"; };
-          ipv6_enabled = false;
-          name = "podman";
-          network_interface = "podman0";
-          subnets = [{ gateway = "10.88.0.1"; subnet = "10.88.0.0/16"; }];
-        } // cfg.defaultNetwork.settings);
+        source = json.generate "podman.json" networkConfig;
       };
 
+      # containers cannot reach aardvark-dns otherwise
+      networking.firewall.interfaces.${network_interface}.allowedUDPPorts = lib.mkIf dns_enabled [ 53 ];
+
       virtualisation.containers = {
         enable = true; # Enable common /etc/containers configuration
         containersConf.settings = {
diff --git a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
index 3d7f3ccb62f8..55a214325118 100644
--- a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix
@@ -701,7 +701,10 @@ in
           type = types.listOf types.str;
           default = [];
           example = [ "-vga std" ];
-          description = lib.mdDoc "Options passed to QEMU.";
+          description = lib.mdDoc ''
+            Options passed to QEMU.
+            See [QEMU User Documentation](https://www.qemu.org/docs/master/system/qemu-manpage) for a complete list.
+          '';
         };
 
       consoles = mkOption {
@@ -732,9 +735,10 @@ in
           description = lib.mdDoc ''
             Networking-related command-line options that should be passed to qemu.
             The default is to use userspace networking (SLiRP).
+            See the [QEMU Wiki on Networking](https://wiki.qemu.org/Documentation/Networking) for details.
 
             If you override this option, be advised to keep
-            ''${QEMU_NET_OPTS:+,$QEMU_NET_OPTS} (as seen in the example)
+            `''${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}` (as seen in the example)
             to keep the default runtime behaviour.
           '';
         };
@@ -809,14 +813,19 @@ in
           defaultText = "!cfg.useBootLoader";
           description =
             lib.mdDoc ''
-              If enabled, the virtual machine will boot directly into the kernel instead of through a bootloader. Other relevant parameters such as the initrd are also passed to QEMU.
+              If enabled, the virtual machine will boot directly into the kernel instead of through a bootloader.
+              Read more about this feature in the [QEMU documentation on Direct Linux Boot](https://qemu-project.gitlab.io/qemu/system/linuxboot.html)
 
+              This is enabled by default.
               If you want to test netboot, consider disabling this option.
+              Enable a bootloader with {option}`virtualisation.useBootLoader` if you need.
 
-              This will not boot / reboot correctly into a system that has switched to a different configuration on disk.
+              Relevant parameters such as those set in `boot.initrd` and `boot.kernelParams` are also passed to QEMU.
+              Additional parameters can be supplied on invocation through the environment variable `$QEMU_KERNEL_PARAMS`.
+              They are added to the `-append` option, see [QEMU User Documentation](https://www.qemu.org/docs/master/system/qemu-manpage) for details
+              For example, to let QEMU use the parent terminal as the serial console, set `QEMU_KERNEL_PARAMS="console=ttyS0"`.
 
-              This is enabled by default if you don't enable bootloaders, but you can still enable a bootloader if you need.
-              Read more about this feature: <https://qemu-project.gitlab.io/qemu/system/linuxboot.html>.
+              This will not (re-)boot correctly into a system that has switched to a different configuration on disk.
             '';
         };
       initrd =
@@ -846,6 +855,8 @@ in
 
             If disabled, the kernel and initrd are directly booted,
             forgoing any bootloader.
+
+            Check the documentation on {option}`virtualisation.directBoot.enable` for details.
           '';
       };
 
@@ -1066,10 +1077,18 @@ in
         ''}
       '';
 
-    systemd.tmpfiles.rules = lib.mkIf config.boot.initrd.systemd.enable [
-      "f /etc/NIXOS 0644 root root -"
-      "d /boot 0644 root root -"
-    ];
+    systemd.tmpfiles.settings."10-qemu-vm" = lib.mkIf config.boot.initrd.systemd.enable {
+      "/etc/NIXOS".f = {
+        mode = "0644";
+        user = "root";
+        group = "root";
+      };
+      "${config.boot.loader.efi.efiSysMountPoint}".d = {
+        mode = "0644";
+        user = "root";
+        group = "root";
+      };
+    };
 
     # After booting, register the closure of the paths in
     # `virtualisation.additionalPaths' in the Nix database in the VM.  This
diff --git a/nixpkgs/nixos/tests/3proxy.nix b/nixpkgs/nixos/tests/3proxy.nix
index 83d39de018a3..b80b4e166d48 100644
--- a/nixpkgs/nixos/tests/3proxy.nix
+++ b/nixpkgs/nixos/tests/3proxy.nix
@@ -134,6 +134,7 @@
   testScript = ''
     start_all()
 
+    peer0.systemctl("start network-online.target")
     peer0.wait_for_unit("network-online.target")
 
     peer1.wait_for_unit("3proxy.service")
diff --git a/nixpkgs/nixos/tests/acme.nix b/nixpkgs/nixos/tests/acme.nix
index e5f2d4c7934a..272782dc2f62 100644
--- a/nixpkgs/nixos/tests/acme.nix
+++ b/nixpkgs/nixos/tests/acme.nix
@@ -522,6 +522,7 @@ in {
           'curl --data \'{"host": "${caDomain}", "addresses": ["${nodes.acme.networking.primaryIPAddress}"]}\' http://${dnsServerIP nodes}:8055/add-a'
       )
 
+      acme.systemctl("start network-online.target")
       acme.wait_for_unit("network-online.target")
       acme.wait_for_unit("pebble.service")
 
diff --git a/nixpkgs/nixos/tests/activation/etc-overlay-immutable.nix b/nixpkgs/nixos/tests/activation/etc-overlay-immutable.nix
new file mode 100644
index 000000000000..70c3623b929c
--- /dev/null
+++ b/nixpkgs/nixos/tests/activation/etc-overlay-immutable.nix
@@ -0,0 +1,30 @@
+{ lib, ... }: {
+
+  name = "activation-etc-overlay-immutable";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes.machine = { pkgs, ... }: {
+    system.etc.overlay.enable = true;
+    system.etc.overlay.mutable = false;
+
+    # Prerequisites
+    systemd.sysusers.enable = true;
+    users.mutableUsers = false;
+    boot.initrd.systemd.enable = true;
+    boot.kernelPackages = pkgs.linuxPackages_latest;
+
+    specialisation.new-generation.configuration = {
+      environment.etc."newgen".text = "newgen";
+    };
+  };
+
+  testScript = ''
+    machine.succeed("findmnt --kernel --type overlay /etc")
+    machine.fail("stat /etc/newgen")
+
+    machine.succeed("/run/current-system/specialisation/new-generation/bin/switch-to-configuration switch")
+
+    assert machine.succeed("cat /etc/newgen") == "newgen"
+  '';
+}
diff --git a/nixpkgs/nixos/tests/activation/etc-overlay-mutable.nix b/nixpkgs/nixos/tests/activation/etc-overlay-mutable.nix
new file mode 100644
index 000000000000..cfe7604fceb8
--- /dev/null
+++ b/nixpkgs/nixos/tests/activation/etc-overlay-mutable.nix
@@ -0,0 +1,30 @@
+{ lib, ... }: {
+
+  name = "activation-etc-overlay-mutable";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes.machine = { pkgs, ... }: {
+    system.etc.overlay.enable = true;
+    system.etc.overlay.mutable = true;
+
+    # Prerequisites
+    boot.initrd.systemd.enable = true;
+    boot.kernelPackages = pkgs.linuxPackages_latest;
+
+    specialisation.new-generation.configuration = {
+      environment.etc."newgen".text = "newgen";
+    };
+  };
+
+  testScript = ''
+    machine.succeed("findmnt --kernel --type overlay /etc")
+    machine.fail("stat /etc/newgen")
+    machine.succeed("echo -n 'mutable' > /etc/mutable")
+
+    machine.succeed("/run/current-system/specialisation/new-generation/bin/switch-to-configuration switch")
+
+    assert machine.succeed("cat /etc/newgen") == "newgen"
+    assert machine.succeed("cat /etc/mutable") == "mutable"
+  '';
+}
diff --git a/nixpkgs/nixos/tests/activation/perlless.nix b/nixpkgs/nixos/tests/activation/perlless.nix
new file mode 100644
index 000000000000..4d784b4542f4
--- /dev/null
+++ b/nixpkgs/nixos/tests/activation/perlless.nix
@@ -0,0 +1,24 @@
+{ lib, ... }:
+
+{
+
+  name = "activation-perlless";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes.machine = { pkgs, modulesPath, ... }: {
+    imports = [ "${modulesPath}/profiles/perlless.nix" ];
+
+    boot.kernelPackages = pkgs.linuxPackages_latest;
+
+    virtualisation.mountHostNixStore = false;
+    virtualisation.useNixStoreImage = true;
+  };
+
+  testScript = ''
+    perl_store_paths = machine.succeed("ls /nix/store | grep perl || true")
+    print(perl_store_paths)
+    assert len(perl_store_paths) == 0
+  '';
+
+}
diff --git a/nixpkgs/nixos/tests/adguardhome.nix b/nixpkgs/nixos/tests/adguardhome.nix
index a6f790b83f5f..80613ce82534 100644
--- a/nixpkgs/nixos/tests/adguardhome.nix
+++ b/nixpkgs/nixos/tests/adguardhome.nix
@@ -126,6 +126,7 @@
 
     with subtest("Testing successful DHCP start"):
         dhcpConf.wait_for_unit("adguardhome.service")
+        client.systemctl("start network-online.target")
         client.wait_for_unit("network-online.target")
         # Test IP assignment via DHCP
         dhcpConf.wait_until_succeeds("ping -c 5 10.0.10.100")
diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix
index 25ee587e8f7a..31af6ec64214 100644
--- a/nixpkgs/nixos/tests/all-tests.nix
+++ b/nixpkgs/nixos/tests/all-tests.nix
@@ -242,7 +242,7 @@ in {
   discourse = handleTest ./discourse.nix {};
   dnscrypt-proxy2 = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy2.nix {};
   dnscrypt-wrapper = runTestOn ["x86_64-linux"] ./dnscrypt-wrapper;
-  dnsdist = handleTest ./dnsdist.nix {};
+  dnsdist = import ./dnsdist.nix { inherit pkgs runTest; };
   doas = handleTest ./doas.nix {};
   docker = handleTestOn ["aarch64-linux" "x86_64-linux"] ./docker.nix {};
   docker-rootless = handleTestOn ["aarch64-linux" "x86_64-linux"] ./docker-rootless.nix {};
@@ -285,6 +285,9 @@ in {
   activation = pkgs.callPackage ../modules/system/activation/test.nix { };
   activation-var = runTest ./activation/var.nix;
   activation-nix-channel = runTest ./activation/nix-channel.nix;
+  activation-etc-overlay-mutable = runTest ./activation/etc-overlay-mutable.nix;
+  activation-etc-overlay-immutable = runTest ./activation/etc-overlay-immutable.nix;
+  activation-perlless = runTest ./activation/perlless.nix;
   etcd = handleTestOn ["x86_64-linux"] ./etcd.nix {};
   etcd-cluster = handleTestOn ["x86_64-linux"] ./etcd-cluster.nix {};
   etebase-server = handleTest ./etebase-server.nix {};
@@ -298,6 +301,7 @@ in {
   fenics = handleTest ./fenics.nix {};
   ferm = handleTest ./ferm.nix {};
   ferretdb = handleTest ./ferretdb.nix {};
+  filesystems-overlayfs = runTest ./filesystems-overlayfs.nix;
   firefox = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox; };
   firefox-beta = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-beta; };
   firefox-devedition = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-devedition; };
@@ -387,6 +391,7 @@ in {
   installed-tests = pkgs.recurseIntoAttrs (handleTest ./installed-tests {});
   invidious = handleTest ./invidious.nix {};
   livebook-service = handleTest ./livebook-service.nix {};
+  pyload = handleTest ./pyload.nix {};
   oci-containers = handleTestOn ["aarch64-linux" "x86_64-linux"] ./oci-containers.nix {};
   odoo = handleTest ./odoo.nix {};
   odoo15 = handleTest ./odoo.nix { package = pkgs.odoo15; };
@@ -421,6 +426,7 @@ in {
   inspircd = handleTest ./inspircd.nix {};
   installer = handleTest ./installer.nix {};
   installer-systemd-stage-1 = handleTest ./installer-systemd-stage-1.nix {};
+  intune = handleTest ./intune.nix {};
   invoiceplane = handleTest ./invoiceplane.nix {};
   iodine = handleTest ./iodine.nix {};
   ipv6 = handleTest ./ipv6.nix {};
@@ -448,6 +454,7 @@ in {
   kerberos = handleTest ./kerberos/default.nix {};
   kernel-generic = handleTest ./kernel-generic.nix {};
   kernel-latest-ath-user-regd = handleTest ./kernel-latest-ath-user-regd.nix {};
+  kernel-rust = handleTestOn ["x86_64-linux"] ./kernel-rust.nix {};
   keter = handleTest ./keter.nix {};
   kexec = handleTest ./kexec.nix {};
   keycloak = discoverTests (import ./keycloak.nix);
@@ -569,8 +576,8 @@ in {
   netdata = handleTest ./netdata.nix {};
   networking.networkd = handleTest ./networking.nix { networkd = true; };
   networking.scripted = handleTest ./networking.nix { networkd = false; };
-  netbox_3_5 = handleTest ./web-apps/netbox.nix { netbox = pkgs.netbox_3_5; };
   netbox_3_6 = handleTest ./web-apps/netbox.nix { netbox = pkgs.netbox_3_6; };
+  netbox_3_7 = handleTest ./web-apps/netbox.nix { netbox = pkgs.netbox_3_7; };
   netbox-upgrade = handleTest ./web-apps/netbox-upgrade.nix {};
   # TODO: put in networking.nix after the test becomes more complete
   networkingProxy = handleTest ./networking-proxy.nix {};
@@ -587,6 +594,7 @@ in {
   nginx-globalredirect = handleTest ./nginx-globalredirect.nix {};
   nginx-http3 = handleTest ./nginx-http3.nix {};
   nginx-modsecurity = handleTest ./nginx-modsecurity.nix {};
+  nginx-moreheaders = handleTest ./nginx-moreheaders.nix {};
   nginx-njs = handleTest ./nginx-njs.nix {};
   nginx-proxyprotocol = handleTest ./nginx-proxyprotocol {};
   nginx-pubhtml = handleTest ./nginx-pubhtml.nix {};
@@ -621,6 +629,7 @@ in {
   ntfy-sh = handleTest ./ntfy-sh.nix {};
   ntfy-sh-migration = handleTest ./ntfy-sh-migration.nix {};
   ntpd-rs = handleTest ./ntpd-rs.nix {};
+  nvmetcfg = handleTest ./nvmetcfg.nix {};
   nzbget = handleTest ./nzbget.nix {};
   nzbhydra2 = handleTest ./nzbhydra2.nix {};
   oh-my-zsh = handleTest ./oh-my-zsh.nix {};
@@ -707,6 +716,7 @@ in {
   power-profiles-daemon = handleTest ./power-profiles-daemon.nix {};
   pppd = handleTest ./pppd.nix {};
   predictable-interface-names = handleTest ./predictable-interface-names.nix {};
+  pretalx = runTest ./web-apps/pretalx.nix;
   printing-socket = handleTest ./printing.nix { socket = true; };
   printing-service = handleTest ./printing.nix { socket = false; };
   privoxy = handleTest ./privoxy.nix {};
@@ -757,6 +767,7 @@ in {
   sabnzbd = handleTest ./sabnzbd.nix {};
   samba = handleTest ./samba.nix {};
   samba-wsdd = handleTest ./samba-wsdd.nix {};
+  sane = handleTest ./sane.nix {};
   sanoid = handleTest ./sanoid.nix {};
   scaphandre = handleTest ./scaphandre.nix {};
   schleuder = handleTest ./schleuder.nix {};
@@ -808,6 +819,7 @@ in {
   stunnel = handleTest ./stunnel.nix {};
   sudo = handleTest ./sudo.nix {};
   sudo-rs = handleTest ./sudo-rs.nix {};
+  suwayomi-server = handleTest ./suwayomi-server.nix {};
   swap-file-btrfs = handleTest ./swap-file-btrfs.nix {};
   swap-partition = handleTest ./swap-partition.nix {};
   swap-random-encryption = handleTest ./swap-random-encryption.nix {};
@@ -850,6 +862,7 @@ in {
   systemd-journal = handleTest ./systemd-journal.nix {};
   systemd-journal-gateway = handleTest ./systemd-journal-gateway.nix {};
   systemd-journal-upload = handleTest ./systemd-journal-upload.nix {};
+  systemd-lock-handler = runTestOn ["aarch64-linux" "x86_64-linux"] ./systemd-lock-handler.nix;
   systemd-machinectl = handleTest ./systemd-machinectl.nix {};
   systemd-networkd = handleTest ./systemd-networkd.nix {};
   systemd-networkd-dhcpserver = handleTest ./systemd-networkd-dhcpserver.nix {};
@@ -864,6 +877,8 @@ in {
   systemd-repart = handleTest ./systemd-repart.nix {};
   systemd-shutdown = handleTest ./systemd-shutdown.nix {};
   systemd-sysupdate = runTest ./systemd-sysupdate.nix;
+  systemd-sysusers-mutable = runTest ./systemd-sysusers-mutable.nix;
+  systemd-sysusers-immutable = runTest ./systemd-sysusers-immutable.nix;
   systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
   systemd-timesyncd-nscd-dnssec = handleTest ./systemd-timesyncd-nscd-dnssec.nix {};
   systemd-user-tmpfiles-rules = handleTest ./systemd-user-tmpfiles-rules.nix {};
@@ -903,6 +918,7 @@ in {
   trilium-server = handleTestOn ["x86_64-linux"] ./trilium-server.nix {};
   tsja = handleTest ./tsja.nix {};
   tsm-client-gui = handleTest ./tsm-client-gui.nix {};
+  ttyd = handleTest ./web-servers/ttyd.nix {};
   txredisapi = handleTest ./txredisapi.nix {};
   tuptime = handleTest ./tuptime.nix {};
   turbovnc-headless-server = handleTest ./turbovnc-headless-server.nix {};
@@ -919,6 +935,7 @@ in {
   upnp.nftables = handleTest ./upnp.nix { useNftables = true; };
   uptermd = handleTest ./uptermd.nix {};
   uptime-kuma = handleTest ./uptime-kuma.nix {};
+  urn-timer = handleTest ./urn-timer.nix {};
   usbguard = handleTest ./usbguard.nix {};
   user-activation-scripts = handleTest ./user-activation-scripts.nix {};
   user-expiry = runTest ./user-expiry.nix;
@@ -942,6 +959,7 @@ in {
   vsftpd = handleTest ./vsftpd.nix {};
   warzone2100 = handleTest ./warzone2100.nix {};
   wasabibackend = handleTest ./wasabibackend.nix {};
+  watchdogd = handleTest ./watchdogd.nix {};
   webhook = runTest ./webhook.nix;
   wiki-js = handleTest ./wiki-js.nix {};
   wine = handleTest ./wine.nix {};
diff --git a/nixpkgs/nixos/tests/appliance-repart-image.nix b/nixpkgs/nixos/tests/appliance-repart-image.nix
index 3f256db84621..861369b9f3ca 100644
--- a/nixpkgs/nixos/tests/appliance-repart-image.nix
+++ b/nixpkgs/nixos/tests/appliance-repart-image.nix
@@ -8,9 +8,8 @@
 let
   rootPartitionLabel = "root";
 
-  bootLoaderConfigPath = "/loader/entries/nixos.conf";
-  kernelPath = "/EFI/nixos/kernel.efi";
-  initrdPath = "/EFI/nixos/initrd.efi";
+  imageId = "nixos-appliance";
+  imageVersion = "1-rc1";
 in
 {
   name = "appliance-gpt-image";
@@ -29,6 +28,9 @@ in
     # TODO(raitobezarius): revisit this when #244907 lands
     boot.loader.grub.enable = false;
 
+    system.image.id = imageId;
+    system.image.version = imageVersion;
+
     virtualisation.fileSystems = lib.mkForce {
       "/" = {
         device = "/dev/disk/by-partlabel/${rootPartitionLabel}";
@@ -38,6 +40,8 @@ in
 
     image.repart = {
       name = "appliance-gpt-image";
+      # OVMF does not work with the default repart sector size of 4096
+      sectorSize = 512;
       partitions = {
         "esp" = {
           contents =
@@ -48,19 +52,8 @@ in
               "/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source =
                 "${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
 
-              # TODO: create an abstraction for Boot Loader Specification (BLS) entries.
-              "${bootLoaderConfigPath}".source = pkgs.writeText "nixos.conf" ''
-                title NixOS
-                linux ${kernelPath}
-                initrd ${initrdPath}
-                options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}
-              '';
-
-              "${kernelPath}".source =
-                "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
-
-              "${initrdPath}".source =
-                "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
+              "/EFI/Linux/${config.system.boot.loader.ukiFile}".source =
+                "${config.system.build.uki}/${config.system.boot.loader.ukiFile}";
             };
           repartConfig = {
             Type = "esp";
@@ -99,7 +92,7 @@ in
       "-f",
       "qcow2",
       "-b",
-      "${nodes.machine.system.build.image}/image.raw",
+      "${nodes.machine.system.build.image}/${nodes.machine.image.repart.imageFile}",
       "-F",
       "raw",
       tmp_disk_image.name,
@@ -108,9 +101,11 @@ in
     # Set NIX_DISK_IMAGE so that the qemu script finds the right disk image.
     os.environ['NIX_DISK_IMAGE'] = tmp_disk_image.name
 
+    os_release = machine.succeed("cat /etc/os-release")
+    assert 'IMAGE_ID="${imageId}"' in os_release
+    assert 'IMAGE_VERSION="${imageVersion}"' in os_release
+
     bootctl_status = machine.succeed("bootctl status")
-    assert "${bootLoaderConfigPath}" in bootctl_status
-    assert "${kernelPath}" in bootctl_status
-    assert "${initrdPath}" in bootctl_status
+    assert "Boot Loader Specification Type #2 (.efi)" in bootctl_status
   '';
 }
diff --git a/nixpkgs/nixos/tests/ayatana-indicators.nix b/nixpkgs/nixos/tests/ayatana-indicators.nix
index bc7ff75f390f..a7de640f9e37 100644
--- a/nixpkgs/nixos/tests/ayatana-indicators.nix
+++ b/nixpkgs/nixos/tests/ayatana-indicators.nix
@@ -4,7 +4,7 @@ in {
   name = "ayatana-indicators";
 
   meta = {
-    maintainers = with lib.maintainers; [ OPNA2608 ];
+    maintainers = lib.teams.lomiri.members;
   };
 
   nodes.machine = { config, ... }: {
@@ -27,17 +27,57 @@ in {
     services.ayatana-indicators = {
       enable = true;
       packages = with pkgs; [
+        ayatana-indicator-datetime
         ayatana-indicator-messages
-      ];
+        ayatana-indicator-session
+      ] ++ (with pkgs.lomiri; [
+        lomiri-indicator-network
+        telephony-service
+      ]);
     };
 
-    # Services needed by some indicators
+    # Setup needed by some indicators
+
     services.accounts-daemon.enable = true; # messages
+
+    # Lomiri-ish setup for Lomiri indicators
+    # TODO move into a Lomiri module, once the package set is far enough for the DE to start
+
+    networking.networkmanager.enable = true; # lomiri-network-indicator
+    # TODO potentially urfkill for lomiri-network-indicator?
+
+    services.dbus.packages = with pkgs.lomiri; [
+      libusermetrics
+    ];
+
+    environment.systemPackages = with pkgs.lomiri; [
+      lomiri-schemas
+    ];
+
+    services.telepathy.enable = true;
+
+    users.users.usermetrics = {
+      group = "usermetrics";
+      home = "/var/lib/usermetrics";
+      createHome = true;
+      isSystemUser = true;
+    };
+
+    users.groups.usermetrics = { };
   };
 
   # TODO session indicator starts up in a semi-broken state, but works fine after a restart. maybe being started before graphical session is truly up & ready?
   testScript = { nodes, ... }: let
-    runCommandPerIndicatorService = command: lib.strings.concatMapStringsSep "\n" command nodes.machine.systemd.user.targets."ayatana-indicators".wants;
+    runCommandOverServiceList = list: command:
+      lib.strings.concatMapStringsSep "\n" command list;
+
+    runCommandOverAyatanaIndicators = runCommandOverServiceList
+      (builtins.filter
+        (service: !(lib.strings.hasPrefix "lomiri" service || lib.strings.hasPrefix "telephony-service" service))
+        nodes.machine.systemd.user.targets."ayatana-indicators".wants);
+
+    runCommandOverAllIndicators = runCommandOverServiceList
+      nodes.machine.systemd.user.targets."ayatana-indicators".wants;
   in ''
     start_all()
     machine.wait_for_x()
@@ -50,8 +90,8 @@ in {
     machine.sleep(10)
 
     # Now check if all indicators were brought up successfully, and kill them for later
-  '' + (runCommandPerIndicatorService (service: let serviceExec = builtins.replaceStrings [ "." ] [ "-" ] service; in ''
-    machine.succeed("pgrep -f ${serviceExec}")
+  '' + (runCommandOverAyatanaIndicators (service: let serviceExec = builtins.replaceStrings [ "." ] [ "-" ] service; in ''
+    machine.succeed("pgrep -u ${user} -f ${serviceExec}")
     machine.succeed("pkill -f ${serviceExec}")
   '')) + ''
 
@@ -65,7 +105,7 @@ in {
     machine.sleep(10)
 
     # Now check if all indicator services were brought up successfully
-  '' + runCommandPerIndicatorService (service: ''
+  '' + runCommandOverAllIndicators (service: ''
     machine.wait_for_unit("${service}", "${user}")
   '');
 })
diff --git a/nixpkgs/nixos/tests/babeld.nix b/nixpkgs/nixos/tests/babeld.nix
index d4df6f86d089..e497aa5b64e1 100644
--- a/nixpkgs/nixos/tests/babeld.nix
+++ b/nixpkgs/nixos/tests/babeld.nix
@@ -120,10 +120,6 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
     ''
       start_all()
 
-      client.wait_for_unit("network-online.target")
-      local_router.wait_for_unit("network-online.target")
-      remote_router.wait_for_unit("network-online.target")
-
       local_router.wait_for_unit("babeld.service")
       remote_router.wait_for_unit("babeld.service")
 
diff --git a/nixpkgs/nixos/tests/bittorrent.nix b/nixpkgs/nixos/tests/bittorrent.nix
index 4a73fea6a09d..473b05d4c98e 100644
--- a/nixpkgs/nixos/tests/bittorrent.nix
+++ b/nixpkgs/nixos/tests/bittorrent.nix
@@ -115,6 +115,7 @@ in
       start_all()
 
       # Wait for network and miniupnpd.
+      router.systemctl("start network-online.target")
       router.wait_for_unit("network-online.target")
       router.wait_for_unit("miniupnpd")
 
@@ -129,6 +130,7 @@ in
       tracker.succeed("chmod 644 /tmp/test.torrent")
 
       # Start the tracker.  !!! use a less crappy tracker
+      tracker.systemctl("start network-online.target")
       tracker.wait_for_unit("network-online.target")
       tracker.wait_for_unit("opentracker.service")
       tracker.wait_for_open_port(6969)
@@ -140,6 +142,7 @@ in
 
       # Now we should be able to download from the client behind the NAT.
       tracker.wait_for_unit("httpd")
+      client1.systemctl("start network-online.target")
       client1.wait_for_unit("network-online.target")
       client1.succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent >&2 &")
       client1.wait_for_file("${download-dir}/test.tar.bz2")
@@ -152,6 +155,7 @@ in
 
       # Now download from the second client.  This can only succeed if
       # the first client created a NAT hole in the router.
+      client2.systemctl("start network-online.target")
       client2.wait_for_unit("network-online.target")
       client2.succeed(
           "transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht >&2 &"
diff --git a/nixpkgs/nixos/tests/budgie.nix b/nixpkgs/nixos/tests/budgie.nix
index 19d9b2bd0bed..fe0ed2cf80ed 100644
--- a/nixpkgs/nixos/tests/budgie.nix
+++ b/nixpkgs/nixos/tests/budgie.nix
@@ -33,14 +33,13 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     ''
       with subtest("Wait for login"):
           # wait_for_x() checks graphical-session.target, which is expected to be
-          # inactive on Budgie before #228946 (i.e. systemd managed gnome-session) is
-          # done on upstream.
-          # https://github.com/BuddiesOfBudgie/budgie-desktop/blob/v10.7.2/src/session/budgie-desktop.in#L16
+          # inactive on Budgie before Budgie manages user session with systemd.
+          # https://github.com/BuddiesOfBudgie/budgie-desktop/blob/39e9f0895c978f76/src/session/budgie-desktop.in#L16
           #
           # Previously this was unconditionally touched by xsessionWrapper but was
           # changed in #233981 (we have Budgie:GNOME in XDG_CURRENT_DESKTOP).
           # machine.wait_for_x()
-          machine.wait_until_succeeds('journalctl -t gnome-session-binary --grep "Entering running state"')
+          machine.wait_until_succeeds('journalctl -t budgie-session-binary --grep "Entering running state"')
           machine.wait_for_file("${user.home}/.Xauthority")
           machine.succeed("xauth merge ${user.home}/.Xauthority")
 
diff --git a/nixpkgs/nixos/tests/buildbot.nix b/nixpkgs/nixos/tests/buildbot.nix
index 2f6926313b7c..149d73bba09c 100644
--- a/nixpkgs/nixos/tests/buildbot.nix
+++ b/nixpkgs/nixos/tests/buildbot.nix
@@ -71,6 +71,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     gitrepo.wait_for_unit("multi-user.target")
 
     with subtest("Repo is accessible via git daemon"):
+        bbmaster.systemctl("start network-online.target")
         bbmaster.wait_for_unit("network-online.target")
         bbmaster.succeed("rm -rfv /tmp/fakerepo")
         bbmaster.succeed("git clone git://gitrepo/fakerepo /tmp/fakerepo")
@@ -78,6 +79,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     with subtest("Master service and worker successfully connect"):
         bbmaster.wait_for_unit("buildbot-master.service")
         bbmaster.wait_until_succeeds("curl --fail -s --head http://bbmaster:8010")
+        bbworker.systemctl("start network-online.target")
         bbworker.wait_for_unit("network-online.target")
         bbworker.succeed("nc -z bbmaster 8010")
         bbworker.succeed("nc -z bbmaster 9989")
diff --git a/nixpkgs/nixos/tests/ceph-multi-node.nix b/nixpkgs/nixos/tests/ceph-multi-node.nix
index 556546beee76..b1352a4bc8f4 100644
--- a/nixpkgs/nixos/tests/ceph-multi-node.nix
+++ b/nixpkgs/nixos/tests/ceph-multi-node.nix
@@ -185,6 +185,14 @@ let
     monA.succeed(
         "ceph osd pool create multi-node-test 32 32",
         "ceph osd pool ls | grep 'multi-node-test'",
+
+        # We need to enable an application on the pool, otherwise it will
+        # stay unhealthy in state POOL_APP_NOT_ENABLED.
+        # Creating a CephFS would do this automatically, but we haven't done that here.
+        # See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
+        # We use the custom application name "nixos-test" for this.
+        "ceph osd pool application enable multi-node-test nixos-test",
+
         "ceph osd pool rename multi-node-test multi-node-other-test",
         "ceph osd pool ls | grep 'multi-node-other-test'",
     )
diff --git a/nixpkgs/nixos/tests/ceph-single-node-bluestore.nix b/nixpkgs/nixos/tests/ceph-single-node-bluestore.nix
index acaae4cf300e..8bd1a78244a2 100644
--- a/nixpkgs/nixos/tests/ceph-single-node-bluestore.nix
+++ b/nixpkgs/nixos/tests/ceph-single-node-bluestore.nix
@@ -145,6 +145,14 @@ let
     monA.succeed(
         "ceph osd pool create single-node-test 32 32",
         "ceph osd pool ls | grep 'single-node-test'",
+
+        # We need to enable an application on the pool, otherwise it will
+        # stay unhealthy in state POOL_APP_NOT_ENABLED.
+        # Creating a CephFS would do this automatically, but we haven't done that here.
+        # See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
+        # We use the custom application name "nixos-test" for this.
+        "ceph osd pool application enable single-node-test nixos-test",
+
         "ceph osd pool rename single-node-test single-node-other-test",
         "ceph osd pool ls | grep 'single-node-other-test'",
     )
diff --git a/nixpkgs/nixos/tests/ceph-single-node.nix b/nixpkgs/nixos/tests/ceph-single-node.nix
index a3a4072365af..c34ec511dc6d 100644
--- a/nixpkgs/nixos/tests/ceph-single-node.nix
+++ b/nixpkgs/nixos/tests/ceph-single-node.nix
@@ -145,6 +145,14 @@ let
     monA.succeed(
         "ceph osd pool create single-node-test 32 32",
         "ceph osd pool ls | grep 'single-node-test'",
+
+        # We need to enable an application on the pool, otherwise it will
+        # stay unhealthy in state POOL_APP_NOT_ENABLED.
+        # Creating a CephFS would do this automatically, but we haven't done that here.
+        # See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
+        # We use the custom application name "nixos-test" for this.
+        "ceph osd pool application enable single-node-test nixos-test",
+
         "ceph osd pool rename single-node-test single-node-other-test",
         "ceph osd pool ls | grep 'single-node-other-test'",
     )
@@ -182,19 +190,16 @@ let
     monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
     monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
 
-    # This test has been commented out due to the upstream issue with pyo3
-    # that has broken this dashboard
-    # Reference: https://www.spinics.net/lists/ceph-users/msg77812.html
     # Enable the dashboard and recheck health
-    # monA.succeed(
-    #     "ceph mgr module enable dashboard",
-    #     "ceph config set mgr mgr/dashboard/ssl false",
-    #     # default is 8080 but it's better to be explicit
-    #     "ceph config set mgr mgr/dashboard/server_port 8080",
-    # )
-    # monA.wait_for_open_port(8080)
-    # monA.wait_until_succeeds("curl -q --fail http://localhost:8080")
-    # monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
+    monA.succeed(
+        "ceph mgr module enable dashboard",
+        "ceph config set mgr mgr/dashboard/ssl false",
+        # default is 8080 but it's better to be explicit
+        "ceph config set mgr mgr/dashboard/server_port 8080",
+    )
+    monA.wait_for_open_port(8080)
+    monA.wait_until_succeeds("curl -q --fail http://localhost:8080")
+    monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
   '';
 in {
   name = "basic-single-node-ceph-cluster";
diff --git a/nixpkgs/nixos/tests/cinnamon-wayland.nix b/nixpkgs/nixos/tests/cinnamon-wayland.nix
index 824a606004cc..1629ead16f41 100644
--- a/nixpkgs/nixos/tests/cinnamon-wayland.nix
+++ b/nixpkgs/nixos/tests/cinnamon-wayland.nix
@@ -64,7 +64,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
           # This is not supported at the moment.
           # https://trello.com/b/HHs01Pab/cinnamon-wayland
           machine.execute("${su "cinnamon-screensaver-command -l >&2 &"}")
-          machine.wait_until_succeeds("journalctl -b --grep 'Cinnamon Screensaver is unavailable on Wayland'")
+          machine.wait_until_succeeds("journalctl -b --grep 'cinnamon-screensaver is disabled in wayland sessions'")
 
       with subtest("Open GNOME Terminal"):
           machine.succeed("${su "dbus-launch gnome-terminal"}")
diff --git a/nixpkgs/nixos/tests/cloud-init.nix b/nixpkgs/nixos/tests/cloud-init.nix
index 786e01add7d4..0b4c5a55c80a 100644
--- a/nixpkgs/nixos/tests/cloud-init.nix
+++ b/nixpkgs/nixos/tests/cloud-init.nix
@@ -73,6 +73,7 @@ in makeTest {
   };
   testScript = ''
     # To wait until cloud-init terminates its run
+    unnamed.wait_for_unit("cloud-init-local.service")
     unnamed.wait_for_unit("cloud-final.service")
 
     unnamed.succeed("cat /tmp/cloudinit-write-file | grep -q 'cloudinit'")
diff --git a/nixpkgs/nixos/tests/corerad.nix b/nixpkgs/nixos/tests/corerad.nix
index b6f5d7fc6f75..dd2bec794a1a 100644
--- a/nixpkgs/nixos/tests/corerad.nix
+++ b/nixpkgs/nixos/tests/corerad.nix
@@ -56,6 +56,8 @@ import ./make-test-python.nix (
 
       with subtest("Wait for CoreRAD and network ready"):
           # Ensure networking is online and CoreRAD is ready.
+          router.systemctl("start network-online.target")
+          client.systemctl("start network-online.target")
           router.wait_for_unit("network-online.target")
           client.wait_for_unit("network-online.target")
           router.wait_for_unit("corerad.service")
diff --git a/nixpkgs/nixos/tests/curl-impersonate.nix b/nixpkgs/nixos/tests/curl-impersonate.nix
index 7954e9e5584c..33b10da1dfd0 100644
--- a/nixpkgs/nixos/tests/curl-impersonate.nix
+++ b/nixpkgs/nixos/tests/curl-impersonate.nix
@@ -144,6 +144,8 @@ in {
     start_all()
 
     with subtest("Wait for network"):
+        web.systemctl("start network-online.target")
+        curl.systemctl("start network-online.target")
         web.wait_for_unit("network-online.target")
         curl.wait_for_unit("network-online.target")
 
diff --git a/nixpkgs/nixos/tests/dnsdist.nix b/nixpkgs/nixos/tests/dnsdist.nix
index e72fa05ff282..9921be419a75 100644
--- a/nixpkgs/nixos/tests/dnsdist.nix
+++ b/nixpkgs/nixos/tests/dnsdist.nix
@@ -1,48 +1,113 @@
-import ./make-test-python.nix (
-  { pkgs, ... }: {
-    name = "dnsdist";
-    meta = with pkgs.lib; {
-      maintainers = with maintainers; [ jojosch ];
-    };
+{ pkgs, runTest }:
 
-    nodes.machine = { pkgs, lib, ... }: {
-      services.bind = {
-        enable = true;
-        extraOptions = "empty-zones-enable no;";
-        zones = lib.singleton {
-          name = ".";
-          master = true;
-          file = pkgs.writeText "root.zone" ''
-            $TTL 3600
-            . IN SOA ns.example.org. admin.example.org. ( 1 3h 1h 1w 1d )
-            . IN NS ns.example.org.
-
-            ns.example.org. IN A    192.168.0.1
-            ns.example.org. IN AAAA abcd::1
-
-            1.0.168.192.in-addr.arpa IN PTR ns.example.org.
-          '';
-        };
-      };
-      services.dnsdist = {
-        enable = true;
-        listenPort = 5353;
-        extraConfig = ''
-          newServer({address="127.0.0.1:53", name="local-bind"})
+let
+
+  inherit (pkgs) lib;
+
+  baseConfig = {
+    networking.nameservers = [ "::1" ];
+    services.bind = {
+      enable = true;
+      extraOptions = "empty-zones-enable no;";
+      zones = lib.singleton {
+        name = ".";
+        master = true;
+        file = pkgs.writeText "root.zone" ''
+          $TTL 3600
+          . IN SOA ns.example.org. admin.example.org. ( 1 3h 1h 1w 1d )
+          . IN NS ns.example.org.
+
+          ns.example.org. IN A    192.168.0.1
+          ns.example.org. IN AAAA abcd::1
+
+          1.0.168.192.in-addr.arpa IN PTR ns.example.org.
         '';
       };
-
-      environment.systemPackages = with pkgs; [ dig ];
     };
+    services.dnsdist = {
+      enable = true;
+      listenPort = 5353;
+      extraConfig = ''
+        newServer({address="127.0.0.1:53", name="local-bind"})
+      '';
+    };
+  };
+
+in
+
+{
+
+  base = runTest {
+    name = "dnsdist-base";
+    meta.maintainers = with lib.maintainers; [ jojosch ];
+
+    nodes.machine = baseConfig;
 
     testScript = ''
       machine.wait_for_unit("bind.service")
       machine.wait_for_open_port(53)
-      machine.succeed("dig @127.0.0.1 +short -x 192.168.0.1 | grep -qF ns.example.org")
+      machine.succeed("host -p 53 192.168.0.1 | grep -qF ns.example.org")
 
       machine.wait_for_unit("dnsdist.service")
       machine.wait_for_open_port(5353)
-      machine.succeed("dig @127.0.0.1 -p 5353 +short -x 192.168.0.1 | grep -qF ns.example.org")
+      machine.succeed("host -p 5353 192.168.0.1 | grep -qF ns.example.org")
+    '';
+  };
+
+  dnscrypt = runTest {
+    name = "dnsdist-dnscrypt";
+    meta.maintainers = with lib.maintainers; [ rnhmjoj ];
+
+    nodes.server = lib.mkMerge [
+      baseConfig
+      {
+        networking.firewall.allowedTCPPorts = [ 443 ];
+        networking.firewall.allowedUDPPorts = [ 443 ];
+        services.dnsdist.dnscrypt.enable = true;
+        services.dnsdist.dnscrypt.providerKey = "${./dnscrypt-wrapper/secret.key}";
+      }
+    ];
+
+    nodes.client = {
+      services.dnscrypt-proxy2.enable = true;
+      services.dnscrypt-proxy2.upstreamDefaults = false;
+      services.dnscrypt-proxy2.settings =
+        { server_names = [ "server" ];
+          listen_addresses = [ "[::1]:53" ];
+          cache = false;
+          # Computed using https://dnscrypt.info/stamps/
+          static.server.stamp =
+            "sdns://AQAAAAAAAAAADzE5Mi4xNjguMS4yOjQ0MyAUQdg6_RIIpK6pHkINhrv7nxwIG5c7b_m5NJVT3A1AXRYyLmRuc2NyeXB0LWNlcnQuc2VydmVy";
+        };
+      networking.nameservers = [ "::1" ];
+    };
+
+    testScript = ''
+      with subtest("The DNSCrypt server is accepting connections"):
+          server.wait_for_unit("bind.service")
+          server.wait_for_unit("dnsdist.service")
+          server.wait_for_open_port(443)
+          almost_expiration = server.succeed("date --date '14min'").strip()
+
+      with subtest("The DNSCrypt client can connect to the server"):
+          client.wait_until_succeeds("journalctl -u dnscrypt-proxy2 --grep '\[server\] OK'")
+
+      with subtest("DNS queries over UDP are working"):
+          client.wait_for_open_port(53)
+          client.succeed("host -U 192.168.0.1 | grep -qF ns.example.org")
+
+      with subtest("DNS queries over TCP are working"):
+          client.wait_for_open_port(53)
+          client.succeed("host -T 192.168.0.1 | grep -qF ns.example.org")
+
+      with subtest("The server rotates the ephemeral keys"):
+          server.succeed(f"date -s '{almost_expiration}'")
+          client.succeed(f"date -s '{almost_expiration}'")
+          server.wait_until_succeeds("journalctl -u dnsdist --grep 'rotated certificate'")
+
+      with subtest("The client can still connect to the server"):
+          client.wait_until_succeeds("host -T 192.168.0.1")
+          client.wait_until_succeeds("host -U 192.168.0.1")
     '';
-  }
-)
+  };
+}
diff --git a/nixpkgs/nixos/tests/dolibarr.nix b/nixpkgs/nixos/tests/dolibarr.nix
index 4fdee9e9698f..95557d317fab 100644
--- a/nixpkgs/nixos/tests/dolibarr.nix
+++ b/nixpkgs/nixos/tests/dolibarr.nix
@@ -1,6 +1,6 @@
 import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "dolibarr";
-  meta.maintainers = [ lib.maintainers.raitobezarius ];
+  meta.maintainers = [ ];
 
   nodes.machine =
     { ... }:
diff --git a/nixpkgs/nixos/tests/elk.nix b/nixpkgs/nixos/tests/elk.nix
index 900ea6320100..b5a8cb532ae0 100644
--- a/nixpkgs/nixos/tests/elk.nix
+++ b/nixpkgs/nixos/tests/elk.nix
@@ -1,6 +1,6 @@
 # To run the test on the unfree ELK use the following command:
 # cd path/to/nixpkgs
-# NIXPKGS_ALLOW_UNFREE=1 nix-build -A nixosTests.elk.unfree.ELK-6
+# NIXPKGS_ALLOW_UNFREE=1 nix-build -A nixosTests.elk.unfree.ELK-7
 
 { system ? builtins.currentSystem,
   config ? {},
@@ -120,7 +120,7 @@ let
               };
 
               elasticsearch-curator = {
-                enable = true;
+                enable = elk ? elasticsearch-curator;
                 actionYAML = ''
                 ---
                 actions:
@@ -246,7 +246,7 @@ let
           one.wait_until_succeeds(
               expect_hits("SuperdupercalifragilisticexpialidociousIndeed")
           )
-    '' + ''
+    '' + lib.optionalString (elk ? elasticsearch-curator) ''
       with subtest("Elasticsearch-curator works"):
           one.systemctl("stop logstash")
           one.systemctl("start elasticsearch-curator")
diff --git a/nixpkgs/nixos/tests/ferm.nix b/nixpkgs/nixos/tests/ferm.nix
index be43877445eb..87c67ac62347 100644
--- a/nixpkgs/nixos/tests/ferm.nix
+++ b/nixpkgs/nixos/tests/ferm.nix
@@ -55,6 +55,8 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     ''
       start_all()
 
+      client.systemctl("start network-online.target")
+      server.systemctl("start network-online.target")
       client.wait_for_unit("network-online.target")
       server.wait_for_unit("network-online.target")
       server.wait_for_unit("ferm.service")
diff --git a/nixpkgs/nixos/tests/filesystems-overlayfs.nix b/nixpkgs/nixos/tests/filesystems-overlayfs.nix
new file mode 100644
index 000000000000..d7cbf640abe4
--- /dev/null
+++ b/nixpkgs/nixos/tests/filesystems-overlayfs.nix
@@ -0,0 +1,89 @@
+{ lib, pkgs, ... }:
+
+let
+  initrdLowerdir = pkgs.runCommand "initrd-lowerdir" { } ''
+    mkdir -p $out
+    echo "initrd" > $out/initrd.txt
+  '';
+  initrdLowerdir2 = pkgs.runCommand "initrd-lowerdir-2" { } ''
+    mkdir -p $out
+    echo "initrd2" > $out/initrd2.txt
+  '';
+  userspaceLowerdir = pkgs.runCommand "userspace-lowerdir" { } ''
+    mkdir -p $out
+    echo "userspace" > $out/userspace.txt
+  '';
+  userspaceLowerdir2 = pkgs.runCommand "userspace-lowerdir-2" { } ''
+    mkdir -p $out
+    echo "userspace2" > $out/userspace2.txt
+  '';
+in
+{
+
+  name = "writable-overlays";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes.machine = { config, pkgs, ... }: {
+    boot.initrd.systemd.enable = true;
+    boot.initrd.availableKernelModules = [ "overlay" ];
+
+    virtualisation.fileSystems = {
+      "/initrd-overlay" = {
+        overlay = {
+          lowerdir = [ initrdLowerdir ];
+          upperdir = "/.rw-initrd-overlay/upper";
+          workdir = "/.rw-initrd-overlay/work";
+        };
+        neededForBoot = true;
+      };
+      "/userspace-overlay" = {
+        overlay = {
+          lowerdir = [ userspaceLowerdir ];
+          upperdir = "/.rw-userspace-overlay/upper";
+          workdir = "/.rw-userspace-overlay/work";
+        };
+      };
+      "/ro-initrd-overlay" = {
+        overlay.lowerdir = [
+          initrdLowerdir
+          initrdLowerdir2
+        ];
+        neededForBoot = true;
+      };
+      "/ro-userspace-overlay" = {
+        overlay.lowerdir = [
+          userspaceLowerdir
+          userspaceLowerdir2
+        ];
+      };
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("default.target")
+
+    with subtest("Initrd overlay"):
+      machine.wait_for_file("/initrd-overlay/initrd.txt", 5)
+      machine.succeed("touch /initrd-overlay/writable.txt")
+      machine.succeed("findmnt --kernel --types overlay /initrd-overlay")
+
+    with subtest("Userspace overlay"):
+      machine.wait_for_file("/userspace-overlay/userspace.txt", 5)
+      machine.succeed("touch /userspace-overlay/writable.txt")
+      machine.succeed("findmnt --kernel --types overlay /userspace-overlay")
+
+    with subtest("Read only initrd overlay"):
+      machine.wait_for_file("/ro-initrd-overlay/initrd.txt", 5)
+      machine.wait_for_file("/ro-initrd-overlay/initrd2.txt", 5)
+      machine.fail("touch /ro-initrd-overlay/not-writable.txt")
+      machine.succeed("findmnt --kernel --types overlay /ro-initrd-overlay")
+
+    with subtest("Read only userspace overlay"):
+      machine.wait_for_file("/ro-userspace-overlay/userspace.txt", 5)
+      machine.wait_for_file("/ro-userspace-overlay/userspace2.txt", 5)
+      machine.fail("touch /ro-userspace-overlay/not-writable.txt")
+      machine.succeed("findmnt --kernel --types overlay /ro-userspace-overlay")
+  '';
+
+}
diff --git a/nixpkgs/nixos/tests/freetube.nix b/nixpkgs/nixos/tests/freetube.nix
index f285384b68e0..faa534938227 100644
--- a/nixpkgs/nixos/tests/freetube.nix
+++ b/nixpkgs/nixos/tests/freetube.nix
@@ -23,6 +23,8 @@ let
       inherit name;
       nodes = { "${name}" = machine; };
       meta.maintainers = with pkgs.lib.maintainers; [ kirillrdy ];
+      # time-out on ofborg
+      meta.broken = pkgs.stdenv.isAarch64;
       enableOCR = true;
 
       testScript = ''
diff --git a/nixpkgs/nixos/tests/frigate.nix b/nixpkgs/nixos/tests/frigate.nix
index 836fe0d063f8..03bd2b89611d 100644
--- a/nixpkgs/nixos/tests/frigate.nix
+++ b/nixpkgs/nixos/tests/frigate.nix
@@ -41,6 +41,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} :
         serviceConfig = {
           DynamicUser = true;
           ExecStart = "${lib.getBin pkgs.ffmpeg-headless}/bin/ffmpeg -re -f lavfi -i smptebars=size=800x600:rate=10 -f mpegts -listen 1 http://0.0.0.0:8080";
+          Restart = "always";
         };
       };
     };
@@ -51,10 +52,14 @@ import ./make-test-python.nix ({ pkgs, lib, ...} :
 
     machine.wait_for_unit("frigate.service")
 
+    # Frigate startup
     machine.wait_for_open_port(5001)
 
-    machine.succeed("curl http://localhost:5001")
+    # nginx startup
+    machine.wait_for_open_port(80)
 
-    machine.wait_for_file("/var/cache/frigate/test-*.mp4")
+    machine.succeed("curl http://localhost")
+
+    machine.wait_for_file("/var/cache/frigate/test@*.mp4")
   '';
 })
diff --git a/nixpkgs/nixos/tests/gitdaemon.nix b/nixpkgs/nixos/tests/gitdaemon.nix
index bb07b6e97b7f..052fa902b450 100644
--- a/nixpkgs/nixos/tests/gitdaemon.nix
+++ b/nixpkgs/nixos/tests/gitdaemon.nix
@@ -59,6 +59,9 @@ in {
     with subtest("git daemon starts"):
         server.wait_for_unit("git-daemon.service")
 
+
+    server.systemctl("start network-online.target")
+    client.systemctl("start network-online.target")
     server.wait_for_unit("network-online.target")
     client.wait_for_unit("network-online.target")
 
diff --git a/nixpkgs/nixos/tests/gitlab.nix b/nixpkgs/nixos/tests/gitlab.nix
index 8d3126425311..c4d69a56c93a 100644
--- a/nixpkgs/nixos/tests/gitlab.nix
+++ b/nixpkgs/nixos/tests/gitlab.nix
@@ -419,7 +419,7 @@ in {
       gitlab.systemctl("start gitlab-backup.service")
       gitlab.wait_for_unit("gitlab-backup.service")
       gitlab.wait_for_file("${nodes.gitlab.services.gitlab.statePath}/backup/dump_gitlab_backup.tar")
-      gitlab.systemctl("stop postgresql.service gitlab.target")
+      gitlab.systemctl("stop postgresql.service gitlab-config.service gitlab.target")
       gitlab.succeed(
           "find ${nodes.gitlab.services.gitlab.statePath} -mindepth 1 -maxdepth 1 -not -name backup -execdir rm -r {} +"
       )
diff --git a/nixpkgs/nixos/tests/gnome-extensions.nix b/nixpkgs/nixos/tests/gnome-extensions.nix
index 2faff9a4a80d..a9bb5e3766b7 100644
--- a/nixpkgs/nixos/tests/gnome-extensions.nix
+++ b/nixpkgs/nixos/tests/gnome-extensions.nix
@@ -86,7 +86,7 @@ import ./make-test-python.nix (
       "ddterm"
       "emoji-selector"
       "gsconnect"
-      "system-monitor"
+      "system-monitor-next"
       "desktop-icons-ng-ding"
       "workspace-indicator"
       "vitals"
diff --git a/nixpkgs/nixos/tests/guix/publish.nix b/nixpkgs/nixos/tests/guix/publish.nix
index a15e00b0fa98..eb56fc97478c 100644
--- a/nixpkgs/nixos/tests/guix/publish.nix
+++ b/nixpkgs/nixos/tests/guix/publish.nix
@@ -80,6 +80,7 @@ in {
 
     # Now it's the client turn to make use of it.
     substitute_server = "http://server.local:${toString publishPort}"
+    client.systemctl("start network-online.target")
     client.wait_for_unit("network-online.target")
     response = client.succeed(f"curl {substitute_server}")
     assert "Guix Substitute Server" in response
diff --git a/nixpkgs/nixos/tests/haproxy.nix b/nixpkgs/nixos/tests/haproxy.nix
index 555474d7f299..173093873757 100644
--- a/nixpkgs/nixos/tests/haproxy.nix
+++ b/nixpkgs/nixos/tests/haproxy.nix
@@ -1,22 +1,42 @@
-import ./make-test-python.nix ({ pkgs, ...}: {
+import ./make-test-python.nix ({ lib, pkgs, ...}: {
   name = "haproxy";
   nodes = {
-    machine = { ... }: {
-      services.haproxy = {
+    server = { ... }: {
+     services.haproxy = {
         enable = true;
         config = ''
+          global
+            limited-quic
+
           defaults
+            mode http
             timeout connect 10s
+            timeout client 10s
+            timeout server 10s
+
+            log /dev/log local0 debug err
+            option logasap
+            option httplog
+            option httpslog
 
           backend http_server
-            mode http
-            server httpd [::1]:8000
+            server httpd [::1]:8000 alpn http/1.1
 
           frontend http
-            bind *:80
-            mode http
+            bind :80
+            bind :443 ssl strict-sni crt /etc/ssl/fullchain.pem alpn h2,http/1.1
+            bind quic4@:443 ssl strict-sni crt /etc/ssl/fullchain.pem alpn h3 allow-0rtt
+
+            http-after-response add-header alt-svc 'h3=":443"; ma=60' if { ssl_fc }
+
             http-request use-service prometheus-exporter if { path /metrics }
             use_backend http_server
+
+          frontend http-cert-auth
+            bind :8443 ssl strict-sni crt /etc/ssl/fullchain.pem verify required ca-file /etc/ssl/cacert.crt
+            bind quic4@:8443 ssl strict-sni crt /etc/ssl/fullchain.pem verify required ca-file /etc/ssl/cacert.crt alpn h3
+
+            use_backend http_server
         '';
       };
       services.httpd = {
@@ -30,24 +50,75 @@ import ./make-test-python.nix ({ pkgs, ...}: {
           }];
         };
       };
+      networking.firewall.allowedTCPPorts = [ 80 443 8443 ];
+      networking.firewall.allowedUDPPorts = [ 443 8443 ];
+     };
+    client = { ... }: {
+      environment.systemPackages = [ pkgs.curlHTTP3 ];
     };
   };
   testScript = ''
+    # Helpers
+    def cmd(command):
+      print(f"+{command}")
+      r = os.system(command)
+      if r != 0:
+        raise Exception(f"Command {command} failed with exit code {r}")
+
+    def openssl(command):
+      cmd(f"${pkgs.openssl}/bin/openssl {command}")
+
+    # Generate CA.
+    openssl("req -new -newkey rsa:4096 -nodes -x509 -days 7 -subj '/C=ZZ/ST=Cloud/L=Unspecified/O=NixOS/OU=Tests/CN=CA Certificate' -keyout cacert.key -out cacert.crt")
+
+    # Generate and sign Server.
+    openssl("req -newkey rsa:4096 -nodes -subj '/CN=server/OU=Tests/O=NixOS' -keyout server.key -out server.csr")
+    openssl("x509 -req -in server.csr -out server.crt -CA cacert.crt -CAkey cacert.key -days 7")
+    cmd("cat server.crt server.key > fullchain.pem")
+
+    # Generate and sign Client.
+    openssl("req -newkey rsa:4096 -nodes -subj '/CN=client/OU=Tests/O=NixOS' -keyout client.key -out client.csr")
+    openssl("x509 -req -in client.csr -out client.crt -CA cacert.crt -CAkey cacert.key -days 7")
+    cmd("cat client.crt client.key > client.pem")
+
+    # Start the actual test.
     start_all()
-    machine.wait_for_unit("multi-user.target")
-    machine.wait_for_unit("haproxy.service")
-    machine.wait_for_unit("httpd.service")
-    assert "We are all good!" in machine.succeed("curl -fk http://localhost:80/index.txt")
-    assert "haproxy_process_pool_allocated_bytes" in machine.succeed(
-        "curl -fk http://localhost:80/metrics"
-    )
+    server.copy_from_host("fullchain.pem", "/etc/ssl/fullchain.pem")
+    server.copy_from_host("cacert.crt", "/etc/ssl/cacert.crt")
+    server.succeed("chmod 0644 /etc/ssl/fullchain.pem /etc/ssl/cacert.crt")
+
+    client.copy_from_host("cacert.crt", "/etc/ssl/cacert.crt")
+    client.copy_from_host("client.pem", "/root/client.pem")
+
+    server.wait_for_unit("multi-user.target")
+    server.wait_for_unit("haproxy.service")
+    server.wait_for_unit("httpd.service")
+
+    assert "We are all good!" in client.succeed("curl -f http://server/index.txt")
+    assert "haproxy_process_pool_allocated_bytes" in client.succeed("curl -f http://server/metrics")
+
+    with subtest("https"):
+      assert "We are all good!" in client.succeed("curl -f --cacert /etc/ssl/cacert.crt https://server/index.txt")
+
+    with subtest("https-cert-auth"):
+      # Client must succeed in authenticating with the right certificate.
+      assert "We are all good!" in client.succeed("curl -f --cacert /etc/ssl/cacert.crt --cert-type pem --cert /root/client.pem https://server:8443/index.txt")
+      # Client must fail without certificate.
+      client.fail("curl --cacert /etc/ssl/cacert.crt https://server:8443/index.txt")
+
+    with subtest("h3"):
+      assert "We are all good!" in client.succeed("curl -f --http3-only --cacert /etc/ssl/cacert.crt https://server/index.txt")
+
+    with subtest("h3-cert-auth"):
+      # Client must succeed in authenticating with the right certificate.
+      assert "We are all good!" in client.succeed("curl -f --http3-only --cacert /etc/ssl/cacert.crt --cert-type pem --cert /root/client.pem https://server:8443/index.txt")
+      # Client must fail without certificate.
+      client.fail("curl -f --http3-only --cacert /etc/ssl/cacert.crt https://server:8443/index.txt")
 
     with subtest("reload"):
-        machine.succeed("systemctl reload haproxy")
+        server.succeed("systemctl reload haproxy")
         # wait some time to ensure the following request hits the reloaded haproxy
-        machine.sleep(5)
-        assert "We are all good!" in machine.succeed(
-            "curl -fk http://localhost:80/index.txt"
-        )
+        server.sleep(5)
+        assert "We are all good!" in client.succeed("curl -f http://server/index.txt")
   '';
 })
diff --git a/nixpkgs/nixos/tests/hostname.nix b/nixpkgs/nixos/tests/hostname.nix
index 6122e2ffeb83..dffec956bc0b 100644
--- a/nixpkgs/nixos/tests/hostname.nix
+++ b/nixpkgs/nixos/tests/hostname.nix
@@ -34,6 +34,7 @@ let
 
         machine = ${hostName}
 
+        machine.systemctl("start network-online.target")
         machine.wait_for_unit("network-online.target")
 
         # Test if NixOS computes the correct FQDN (either a FQDN or an error/null):
diff --git a/nixpkgs/nixos/tests/incus/container.nix b/nixpkgs/nixos/tests/incus/container.nix
index 2fa1709c7484..0e65cc1e1529 100644
--- a/nixpkgs/nixos/tests/incus/container.nix
+++ b/nixpkgs/nixos/tests/incus/container.nix
@@ -31,7 +31,7 @@ in
 
   testScript = ''
     def instance_is_up(_) -> bool:
-        status, _ = machine.execute("incus exec container --disable-stdin --force-interactive /run/current-system/sw/bin/true")
+        status, _ = machine.execute("incus exec container --disable-stdin --force-interactive /run/current-system/sw/bin/systemctl -- is-system-running")
         return status == 0
 
     def set_container(config):
@@ -81,11 +81,7 @@ in
         assert meminfo_bytes == "125000 kB", f"Wrong amount of memory reported from /proc/meminfo, want: '125000 kB', got: '{meminfo_bytes}'"
 
     with subtest("lxc-container generator configures plain container"):
-        machine.execute("incus delete --force container")
-        machine.succeed("incus launch nixos container")
-        with machine.nested("Waiting for instance to start and be usable"):
-          retry(instance_is_up)
-
+        # reuse the existing container to save some time
         machine.succeed("incus exec container test -- -e /run/systemd/system/service.d/zzz-lxc-service.conf")
 
     with subtest("lxc-container generator configures nested container"):
@@ -103,8 +99,6 @@ in
         machine.succeed("incus launch nixos container --config security.privileged=true")
         with machine.nested("Waiting for instance to start and be usable"):
           retry(instance_is_up)
-        # give generator an extra second to run
-        machine.sleep(1)
 
         machine.succeed("incus exec container test -- -e /run/systemd/system/service.d/zzz-lxc-service.conf")
   '';
diff --git a/nixpkgs/nixos/tests/incus/lxd-to-incus.nix b/nixpkgs/nixos/tests/incus/lxd-to-incus.nix
index 67245b54e752..c0fc98c224df 100644
--- a/nixpkgs/nixos/tests/incus/lxd-to-incus.nix
+++ b/nixpkgs/nixos/tests/incus/lxd-to-incus.nix
@@ -18,8 +18,6 @@ import ../make-test-python.nix (
     nodes.machine =
       { lib, ... }:
       {
-        environment.systemPackages = [ pkgs.lxd-to-incus ];
-
         virtualisation = {
           diskSize = 6144;
           cores = 2;
@@ -77,11 +75,11 @@ import ../make-test-python.nix (
         return ("inactive" in output)
 
       def lxd_instance_is_up(_) -> bool:
-          status, _ = machine.execute("lxc exec container --disable-stdin --force-interactive /run/current-system/sw/bin/true")
+          status, _ = machine.execute("lxc exec container --disable-stdin --force-interactive /run/current-system/sw/bin/systemctl -- is-system-running")
           return status == 0
 
       def incus_instance_is_up(_) -> bool:
-          status, _ = machine.execute("incus exec container --disable-stdin --force-interactive /run/current-system/sw/bin/true")
+          status, _ = machine.execute("incus exec container --disable-stdin --force-interactive /run/current-system/sw/bin/systemctl -- is-system-running")
           return status == 0
 
       with machine.nested("initialize lxd and resources"):
diff --git a/nixpkgs/nixos/tests/incus/virtual-machine.nix b/nixpkgs/nixos/tests/incus/virtual-machine.nix
index 343a25ca7297..c76e4f448f2f 100644
--- a/nixpkgs/nixos/tests/incus/virtual-machine.nix
+++ b/nixpkgs/nixos/tests/incus/virtual-machine.nix
@@ -36,7 +36,7 @@ in
 
   testScript = ''
     def instance_is_up(_) -> bool:
-      status, _ = machine.execute("incus exec ${instance-name} --disable-stdin --force-interactive /run/current-system/sw/bin/true")
+      status, _ = machine.execute("incus exec ${instance-name} --disable-stdin --force-interactive /run/current-system/sw/bin/systemctl -- is-system-running")
       return status == 0
 
     machine.wait_for_unit("incus.service")
diff --git a/nixpkgs/nixos/tests/installed-tests/fwupd.nix b/nixpkgs/nixos/tests/installed-tests/fwupd.nix
index c095a50dc836..fe4f443d7004 100644
--- a/nixpkgs/nixos/tests/installed-tests/fwupd.nix
+++ b/nixpkgs/nixos/tests/installed-tests/fwupd.nix
@@ -1,11 +1,12 @@
-{ pkgs, lib, makeInstalledTest, ... }:
+{ pkgs, makeInstalledTest, ... }:
 
 makeInstalledTest {
   tested = pkgs.fwupd;
 
   testConfig = {
-    services.fwupd.enable = true;
-    services.fwupd.daemonSettings.DisabledPlugins = lib.mkForce [ ]; # don't disable test plugin
-    services.fwupd.enableTestRemote = true;
+    services.fwupd = {
+      enable = true;
+      daemonSettings.TestDevices = true;
+    };
   };
 }
diff --git a/nixpkgs/nixos/tests/installer.nix b/nixpkgs/nixos/tests/installer.nix
index 21d5e1470d8e..7576fae41f83 100644
--- a/nixpkgs/nixos/tests/installer.nix
+++ b/nixpkgs/nixos/tests/installer.nix
@@ -158,7 +158,9 @@ let
       start_all()
       ${optionalString clevisTest ''
       tang.wait_for_unit("sockets.target")
+      tang.systemctl("start network-online.target")
       tang.wait_for_unit("network-online.target")
+      machine.systemctl("start network-online.target")
       machine.wait_for_unit("network-online.target")
       ''}
       machine.wait_for_unit("multi-user.target")
@@ -187,6 +189,7 @@ let
 
       ${optionalString clevisTest ''
         with subtest("Create the Clevis secret with Tang"):
+             machine.systemctl("start network-online.target")
              machine.wait_for_unit("network-online.target")
              machine.succeed('echo -n password | clevis encrypt sss \'{"t": 2, "pins": {"tpm2": {}, "tang": {"url": "http://192.168.1.2"}}}\' -y > /mnt/etc/nixos/clevis-secret.jwe')''}
 
diff --git a/nixpkgs/nixos/tests/intune.nix b/nixpkgs/nixos/tests/intune.nix
new file mode 100644
index 000000000000..41bf638d7661
--- /dev/null
+++ b/nixpkgs/nixos/tests/intune.nix
@@ -0,0 +1,56 @@
+import ./make-test-python.nix ({ pkgs, ...} : {
+  name = "intune";
+  meta = {
+    maintainers = with pkgs.lib.maintainers; [ rhysmdnz ];
+  };
+  enableOCR = true;
+
+  nodes.machine =
+    { nodes, ... }:
+    let user = nodes.machine.users.users.alice;
+    in {
+      services.intune.enable=true;
+      services.gnome.gnome-keyring.enable = true;
+      imports = [ ./common/user-account.nix ./common/x11.nix ];
+      test-support.displayManager.auto.user = user.name;
+      environment = {
+        variables.DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/${builtins.toString user.uid}/bus";
+      };
+    };
+  nodes.pam =
+    { nodes, ... }:
+    let user = nodes.machine.users.users.alice;
+    in {
+      services.intune.enable=true;
+      imports = [ ./common/user-account.nix ];
+    };
+
+  testScript = ''
+    start_all()
+
+    # Check System Daemons successfully start
+    machine.succeed("systemctl start microsoft-identity-device-broker.service")
+    machine.succeed("systemctl start intune-daemon.service")
+
+    # Check User Daemons and intune-portal execurtable works
+    # Going any further than starting it would require internet access and a microsoft account
+    machine.wait_for_x()
+    # TODO: This needs an unlocked user keychain before it will work
+    #machine.succeed("su - alice -c 'systemctl start --user microsoft-identity-broker.service'")
+    machine.succeed("su - alice -c 'systemctl start --user intune-agent.service'")
+    machine.succeed("su - alice -c intune-portal >&2 &")
+    machine.wait_for_text("Intune Agent")
+
+    # Check logging in creates password file
+    def login_as_alice():
+        pam.wait_until_tty_matches("1", "login: ")
+        pam.send_chars("alice\n")
+        pam.wait_until_tty_matches("1", "Password: ")
+        pam.send_chars("foobar\n")
+        pam.wait_until_tty_matches("1", "alice\@pam")
+
+    pam.wait_for_unit("multi-user.target")
+    login_as_alice()
+    pam.wait_for_file("/run/intune/1000/pwquality")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/kanidm.nix b/nixpkgs/nixos/tests/kanidm.nix
index 3f5bca397740..fa24d4a8a5e1 100644
--- a/nixpkgs/nixos/tests/kanidm.nix
+++ b/nixpkgs/nixos/tests/kanidm.nix
@@ -67,6 +67,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
       ''
         start_all()
         server.wait_for_unit("kanidm.service")
+        client.systemctl("start network-online.target")
         client.wait_for_unit("network-online.target")
 
         with subtest("Test HTTP interface"):
diff --git a/nixpkgs/nixos/tests/keepalived.nix b/nixpkgs/nixos/tests/keepalived.nix
index d0bf9d465200..ce291514591f 100644
--- a/nixpkgs/nixos/tests/keepalived.nix
+++ b/nixpkgs/nixos/tests/keepalived.nix
@@ -1,5 +1,6 @@
-import ./make-test-python.nix ({ pkgs, ... }: {
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "keepalived";
+  maintainers = [ lib.maintainers.raitobezarius ];
 
   nodes = {
     node1 = { pkgs, ... }: {
diff --git a/nixpkgs/nixos/tests/kernel-generic.nix b/nixpkgs/nixos/tests/kernel-generic.nix
index 72d31246b75d..0dcab39f3fad 100644
--- a/nixpkgs/nixos/tests/kernel-generic.nix
+++ b/nixpkgs/nixos/tests/kernel-generic.nix
@@ -23,7 +23,7 @@ let
         assert "${linuxPackages.kernel.modDirVersion}" in machine.succeed("uname -a")
       '';
   }) args);
-  kernels = pkgs.linuxKernel.vanillaPackages // {
+  kernels = (removeAttrs pkgs.linuxKernel.vanillaPackages ["__attrsFailEvaluation"]) // {
     inherit (pkgs.linuxKernel.packages)
       linux_4_19_hardened
       linux_5_4_hardened
@@ -32,6 +32,7 @@ let
       linux_6_1_hardened
       linux_6_5_hardened
       linux_6_6_hardened
+      linux_6_7_hardened
       linux_rt_5_4
       linux_rt_5_10
       linux_rt_5_15
diff --git a/nixpkgs/nixos/tests/kernel-rust.nix b/nixpkgs/nixos/tests/kernel-rust.nix
new file mode 100644
index 000000000000..1f269173ec2e
--- /dev/null
+++ b/nixpkgs/nixos/tests/kernel-rust.nix
@@ -0,0 +1,43 @@
+{ system ? builtins.currentSystem
+, config ? { }
+, pkgs ? import ../.. { inherit system config; }
+}:
+
+let
+  inherit (pkgs.lib) const filterAttrs mapAttrs;
+
+  kernelRustTest = kernelPackages: import ./make-test-python.nix ({ lib, ... }: {
+    name = "kernel-rust";
+    meta.maintainers = with lib.maintainers; [ blitz ma27 ];
+    nodes.machine = { config, ... }: {
+      boot = {
+        inherit kernelPackages;
+        extraModulePackages = [ config.boot.kernelPackages.rust-out-of-tree-module ];
+        kernelPatches = [
+          {
+            name = "Rust Support";
+            patch = null;
+            features = {
+              rust = true;
+            };
+          }
+        ];
+      };
+    };
+    testScript = ''
+      machine.wait_for_unit("default.target")
+      machine.succeed("modprobe rust_out_of_tree")
+    '';
+  });
+
+  kernels = {
+    inherit (pkgs.linuxKernel.packages) linux_testing;
+  }
+  // filterAttrs
+    (const (x: let
+      inherit (builtins.tryEval (
+        x.rust-out-of-tree-module or null != null
+      )) success value;
+    in success && value))
+    pkgs.linuxKernel.vanillaPackages;
+in mapAttrs (const kernelRustTest) kernels
diff --git a/nixpkgs/nixos/tests/lemmy.nix b/nixpkgs/nixos/tests/lemmy.nix
index de2c4938fe23..e8d747f89a9e 100644
--- a/nixpkgs/nixos/tests/lemmy.nix
+++ b/nixpkgs/nixos/tests/lemmy.nix
@@ -59,6 +59,7 @@ in
         server.succeed("curl --fail localhost:${toString uiPort}")
 
     with subtest("Lemmy-UI responds through the caddy reverse proxy"):
+        server.systemctl("start network-online.target")
         server.wait_for_unit("network-online.target")
         server.wait_for_unit("caddy.service")
         server.wait_for_open_port(80)
@@ -66,6 +67,7 @@ in
         assert "Lemmy" in body, f"String Lemmy not found in response for ${lemmyNodeName}: \n{body}"
 
     with subtest("the server is exposed externally"):
+        client.systemctl("start network-online.target")
         client.wait_for_unit("network-online.target")
         client.succeed("curl -v --fail ${lemmyNodeName}")
 
diff --git a/nixpkgs/nixos/tests/livebook-service.nix b/nixpkgs/nixos/tests/livebook-service.nix
index 56b4eb932f34..f428412e1644 100644
--- a/nixpkgs/nixos/tests/livebook-service.nix
+++ b/nixpkgs/nixos/tests/livebook-service.nix
@@ -9,13 +9,15 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
 
       services.livebook = {
         enableUserService = true;
-        port = 20123;
+        environment = {
+          LIVEBOOK_PORT = 20123;
+          LIVEBOOK_COOKIE = "chocolate chip";
+          LIVEBOOK_TOKEN_ENABLED = true;
+
+        };
         environmentFile = pkgs.writeText "livebook.env" ''
           LIVEBOOK_PASSWORD = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
         '';
-        options = {
-          cookie = "chocolate chip";
-        };
       };
     };
   };
diff --git a/nixpkgs/nixos/tests/miriway.nix b/nixpkgs/nixos/tests/miriway.nix
index f12c4d5ecc41..a0987d9fc41b 100644
--- a/nixpkgs/nixos/tests/miriway.nix
+++ b/nixpkgs/nixos/tests/miriway.nix
@@ -31,7 +31,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
         enable-x11=
 
         ctrl-alt=t:foot --maximized
-        ctrl-alt=a:env WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY=invalid alacritty --option window.startup_mode=maximized
+        ctrl-alt=a:env WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY= alacritty --option window.startup_mode=\"maximized\"
 
         shell-component=dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY
 
diff --git a/nixpkgs/nixos/tests/netbird.nix b/nixpkgs/nixos/tests/netbird.nix
index ef793cfe9881..7342e8d04a39 100644
--- a/nixpkgs/nixos/tests/netbird.nix
+++ b/nixpkgs/nixos/tests/netbird.nix
@@ -14,7 +14,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
 
   testScript = ''
     start_all()
-    node.wait_for_unit("netbird.service")
+    node.wait_for_unit("netbird-wt0.service")
     node.wait_for_file("/var/run/netbird/sock")
     node.succeed("netbird status | grep -q 'Daemon status: NeedsLogin'")
   '';
diff --git a/nixpkgs/nixos/tests/networking.nix b/nixpkgs/nixos/tests/networking.nix
index 768d0cfa2238..6bd89902eedb 100644
--- a/nixpkgs/nixos/tests/networking.nix
+++ b/nixpkgs/nixos/tests/networking.nix
@@ -130,6 +130,7 @@ let
           start_all()
 
           client.wait_for_unit("network.target")
+          router.systemctl("start network-online.target")
           router.wait_for_unit("network-online.target")
 
           with subtest("Make sure DHCP server is not started"):
@@ -222,6 +223,7 @@ let
           start_all()
 
           client.wait_for_unit("network.target")
+          router.systemctl("start network-online.target")
           router.wait_for_unit("network-online.target")
 
           with subtest("Wait until we have an ip address on each interface"):
@@ -849,6 +851,7 @@ let
 
           client.wait_for_unit("network.target")
           client_with_privacy.wait_for_unit("network.target")
+          router.systemctl("start network-online.target")
           router.wait_for_unit("network-online.target")
 
           with subtest("Wait until we have an ip address"):
diff --git a/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix b/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
index addc898bd760..b09ee1276a13 100644
--- a/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
+++ b/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
@@ -41,7 +41,7 @@ in {
         };
         secretFile = "/etc/nextcloud-secrets.json";
 
-        extraOptions = {
+        settings = {
           allow_local_remote_servers = true;
           redis = {
             dbindex = 0;
diff --git a/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix b/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix
index d95af8a89d07..3c090f0d3c3b 100644
--- a/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix
+++ b/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix
@@ -41,7 +41,7 @@ in {
         extraApps = {
           inherit (pkgs."nextcloud${lib.versions.major config.services.nextcloud.package.version}Packages".apps) notify_push;
         };
-        extraOptions.trusted_proxies = [ "::1" ];
+        settings.trusted_proxies = [ "::1" ];
       };
 
       services.redis.servers."nextcloud".enable = true;
diff --git a/nixpkgs/nixos/tests/nfs/kerberos.nix b/nixpkgs/nixos/tests/nfs/kerberos.nix
index 1bace4058be5..5944b53319a0 100644
--- a/nixpkgs/nixos/tests/nfs/kerberos.nix
+++ b/nixpkgs/nixos/tests/nfs/kerberos.nix
@@ -105,6 +105,7 @@ in
       server.wait_for_unit("rpc-gssd.service")
       server.wait_for_unit("rpc-svcgssd.service")
 
+      client.systemctl("start network-online.target")
       client.wait_for_unit("network-online.target")
 
       # add principals to client keytab
diff --git a/nixpkgs/nixos/tests/nginx-moreheaders.nix b/nixpkgs/nixos/tests/nginx-moreheaders.nix
new file mode 100644
index 000000000000..560dcf9ce0b8
--- /dev/null
+++ b/nixpkgs/nixos/tests/nginx-moreheaders.nix
@@ -0,0 +1,37 @@
+import ./make-test-python.nix {
+  name = "nginx-more-headers";
+
+  nodes = {
+    webserver = { pkgs, ... }: {
+      services.nginx = {
+        enable = true;
+
+        virtualHosts.test = {
+          locations = {
+            "/".return = "200 blub";
+            "/some" =  {
+              return = "200 blub";
+              extraConfig = ''
+                more_set_headers "Referrer-Policy: no-referrer";
+              '';
+            };
+          };
+          extraConfig = ''
+            more_set_headers "X-Powered-By: nixos";
+          '';
+        };
+      };
+    };
+  };
+
+  testScript = ''
+    webserver.wait_for_unit("nginx")
+    webserver.wait_for_open_port(80)
+
+    webserver.succeed("curl --fail --resolve test:80:127.0.0.1 --head --verbose http://test | grep -q \"X-Powered-By: nixos\"")
+    webserver.fail("curl --fail --resolve test:80:127.0.0.1 --head --verbose http://test | grep -q \"Referrer-Policy: no-referrer\"")
+
+    webserver.succeed("curl --fail --resolve test:80:127.0.0.1 --head --verbose http://test/some | grep -q \"X-Powered-By: nixos\"")
+    webserver.succeed("curl --fail --resolve test:80:127.0.0.1 --head --verbose http://test/some | grep -q \"Referrer-Policy: no-referrer\"")
+  '';
+}
diff --git a/nixpkgs/nixos/tests/nixops/default.nix b/nixpkgs/nixos/tests/nixops/default.nix
index f7a26f2461c4..6501d13a2ed3 100644
--- a/nixpkgs/nixos/tests/nixops/default.nix
+++ b/nixpkgs/nixos/tests/nixops/default.nix
@@ -1,6 +1,4 @@
-{ pkgs
-, testers
-, ... }:
+{ pkgs, ... }:
 let
   inherit (pkgs) lib;
 
@@ -21,7 +19,7 @@ let
     passthru.override = args': testsForPackage (args // args');
   };
 
-  testLegacyNetwork = { nixopsPkg, ... }: testers.nixosTest ({
+  testLegacyNetwork = { nixopsPkg, ... }: pkgs.testers.nixosTest ({
     name = "nixops-legacy-network";
     nodes = {
       deployer = { config, lib, nodes, pkgs, ... }: {
diff --git a/nixpkgs/nixos/tests/nixos-rebuild-target-host.nix b/nixpkgs/nixos/tests/nixos-rebuild-target-host.nix
index 8d60b788abf3..bf80b2fa6606 100644
--- a/nixpkgs/nixos/tests/nixos-rebuild-target-host.nix
+++ b/nixpkgs/nixos/tests/nixos-rebuild-target-host.nix
@@ -132,5 +132,10 @@ import ./make-test-python.nix ({ pkgs, ... }: {
         deployer.succeed("passh -c 3 -C -p ${nodes.target.users.users.bob.password} -P \"\[sudo\] password\" nixos-rebuild switch -I nixos-config=/root/configuration-3.nix --target-host bob@target --use-remote-sudo &>/dev/console")
         target_hostname = deployer.succeed("ssh alice@target cat /etc/hostname").rstrip()
         assert target_hostname == "config-3-deployed", f"{target_hostname=}"
+
+      with subtest("Deploy works with very long TMPDIR"):
+        tmp_dir = "/var/folder/veryveryveryveryverylongpathnamethatdoesnotworkwithcontrolpath"
+        deployer.succeed(f"mkdir -p {tmp_dir}")
+        deployer.succeed(f"TMPDIR={tmp_dir} nixos-rebuild switch -I nixos-config=/root/configuration-1.nix --target-host root@target &>/dev/console")
     '';
 })
diff --git a/nixpkgs/nixos/tests/nvmetcfg.nix b/nixpkgs/nixos/tests/nvmetcfg.nix
new file mode 100644
index 000000000000..a4c459a343cf
--- /dev/null
+++ b/nixpkgs/nixos/tests/nvmetcfg.nix
@@ -0,0 +1,43 @@
+import ./make-test-python.nix ({ lib, ... }: {
+  name = "nvmetcfg";
+
+  meta = {
+    maintainers = with lib.maintainers; [ nickcao ];
+  };
+
+  nodes = {
+    server = { pkgs, ... }: {
+      boot.kernelModules = [ "nvmet" ];
+      environment.systemPackages = [ pkgs.nvmetcfg ];
+      networking.firewall.allowedTCPPorts = [ 4420 ];
+      virtualisation.emptyDiskImages = [ 512 ];
+    };
+    client = { pkgs, ... }: {
+      boot.kernelModules = [ "nvme-fabrics" ];
+      environment.systemPackages = [ pkgs.nvme-cli ];
+    };
+  };
+
+  testScript = let subsystem = "nqn.2014-08.org.nixos:server"; in ''
+    import json
+
+    with subtest("Create subsystem and namespace"):
+      server.succeed("nvmet subsystem add ${subsystem}")
+      server.succeed("nvmet namespace add ${subsystem} 1 /dev/vdb")
+
+    with subtest("Bind subsystem to port"):
+      server.wait_for_unit("network-online.target")
+      server.succeed("nvmet port add 1 tcp 0.0.0.0:4420")
+      server.succeed("nvmet port add-subsystem 1 ${subsystem}")
+
+    with subtest("Discover and connect to available subsystems"):
+      client.wait_for_unit("network-online.target")
+      assert "subnqn:  ${subsystem}" in client.succeed("nvme discover --transport=tcp --traddr=server --trsvcid=4420")
+      client.succeed("nvme connect-all --transport=tcp --traddr=server --trsvcid=4420")
+
+    with subtest("Write to the connected subsystem"):
+      devices = json.loads(client.succeed("lsblk --nvme --paths --json"))["blockdevices"]
+      assert len(devices) == 1
+      client.succeed(f"dd if=/dev/zero of={devices[0]['name']} bs=1M count=64")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/oci-containers.nix b/nixpkgs/nixos/tests/oci-containers.nix
index 205ce623d089..1f8e276204a8 100644
--- a/nixpkgs/nixos/tests/oci-containers.nix
+++ b/nixpkgs/nixos/tests/oci-containers.nix
@@ -24,6 +24,10 @@ let
             ports = ["8181:80"];
           };
         };
+
+        # Stop systemd from killing remaining processes if ExecStop script
+        # doesn't work, so that proper stopping can be tested.
+        systemd.services."${backend}-nginx".serviceConfig.KillSignal = "SIGCONT";
       };
     };
 
@@ -32,6 +36,7 @@ let
       ${backend}.wait_for_unit("${backend}-nginx.service")
       ${backend}.wait_for_open_port(8181)
       ${backend}.wait_until_succeeds("curl -f http://localhost:8181 | grep Hello")
+      ${backend}.succeed("systemctl stop ${backend}-nginx.service", timeout=10)
     '';
   };
 
diff --git a/nixpkgs/nixos/tests/opensmtpd-rspamd.nix b/nixpkgs/nixos/tests/opensmtpd-rspamd.nix
index 19969a7b47dd..e413a2050bd6 100644
--- a/nixpkgs/nixos/tests/opensmtpd-rspamd.nix
+++ b/nixpkgs/nixos/tests/opensmtpd-rspamd.nix
@@ -119,6 +119,7 @@ import ./make-test-python.nix {
   testScript = ''
     start_all()
 
+    client.systemctl("start network-online.target")
     client.wait_for_unit("network-online.target")
     smtp1.wait_for_unit("opensmtpd")
     smtp2.wait_for_unit("opensmtpd")
diff --git a/nixpkgs/nixos/tests/opensmtpd.nix b/nixpkgs/nixos/tests/opensmtpd.nix
index 17c1a569ba0d..d32f82ed33b8 100644
--- a/nixpkgs/nixos/tests/opensmtpd.nix
+++ b/nixpkgs/nixos/tests/opensmtpd.nix
@@ -104,6 +104,7 @@ import ./make-test-python.nix {
   testScript = ''
     start_all()
 
+    client.systemctl("start network-online.target")
     client.wait_for_unit("network-online.target")
     smtp1.wait_for_unit("opensmtpd")
     smtp2.wait_for_unit("opensmtpd")
diff --git a/nixpkgs/nixos/tests/owncast.nix b/nixpkgs/nixos/tests/owncast.nix
index debb34f5009d..73aac4e70475 100644
--- a/nixpkgs/nixos/tests/owncast.nix
+++ b/nixpkgs/nixos/tests/owncast.nix
@@ -31,6 +31,8 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   testScript = ''
     start_all()
 
+    client.systemctl("start network-online.target")
+    server.systemctl("start network-online.target")
     client.wait_for_unit("network-online.target")
     server.wait_for_unit("network-online.target")
     server.wait_for_unit("owncast.service")
diff --git a/nixpkgs/nixos/tests/podman/default.nix b/nixpkgs/nixos/tests/podman/default.nix
index 0e1f420f2a7d..3eea45832f0a 100644
--- a/nixpkgs/nixos/tests/podman/default.nix
+++ b/nixpkgs/nixos/tests/podman/default.nix
@@ -24,8 +24,6 @@ import ../make-test-python.nix (
         virtualisation.podman.enable = true;
 
         virtualisation.podman.defaultNetwork.settings.dns_enabled = true;
-
-        networking.firewall.allowedUDPPorts = [ 53 ];
       };
       docker = { pkgs, ... }: {
         virtualisation.podman.enable = true;
diff --git a/nixpkgs/nixos/tests/pomerium.nix b/nixpkgs/nixos/tests/pomerium.nix
index abaf56c518e0..d0204488e8ef 100644
--- a/nixpkgs/nixos/tests/pomerium.nix
+++ b/nixpkgs/nixos/tests/pomerium.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "pomerium";
   meta = with lib.maintainers; {
-    maintainers = [ lukegb ];
+    maintainers = [ lukegb devusb ];
   };
 
   nodes = let base = myIP: { pkgs, lib, ... }: {
@@ -103,7 +103,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     with subtest("ui"):
         pomerium.succeed(
           # check for a string that only appears if the UI is displayed correctly
-            "chromium --no-sandbox --headless --disable-gpu --dump-dom --host-resolver-rules='MAP login.required 127.0.0.1:80' http://login.required/.pomerium | grep 'contact your administrator'"
+            "chromium --no-sandbox --headless --disable-gpu --dump-dom --host-resolver-rules='MAP login.required 127.0.0.1:80' http://login.required/.pomerium | grep 'User Details Not Available'"
         )
   '';
 })
diff --git a/nixpkgs/nixos/tests/postgis.nix b/nixpkgs/nixos/tests/postgis.nix
index 09c738b938ba..dacf4e576c07 100644
--- a/nixpkgs/nixos/tests/postgis.nix
+++ b/nixpkgs/nixos/tests/postgis.nix
@@ -24,6 +24,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     master.wait_for_unit("postgresql")
     master.sleep(10)  # Hopefully this is long enough!!
     master.succeed("sudo -u postgres psql -c 'CREATE EXTENSION postgis;'")
+    master.succeed("sudo -u postgres psql -c 'CREATE EXTENSION postgis_raster;'")
     master.succeed("sudo -u postgres psql -c 'CREATE EXTENSION postgis_topology;'")
   '';
 })
diff --git a/nixpkgs/nixos/tests/prometheus-exporters.nix b/nixpkgs/nixos/tests/prometheus-exporters.nix
index 5872b02b609e..7e74f27174ec 100644
--- a/nixpkgs/nixos/tests/prometheus-exporters.nix
+++ b/nixpkgs/nixos/tests/prometheus-exporters.nix
@@ -257,21 +257,6 @@ let
       '';
     };
 
-    exportarr-sonarr = {
-      nodeName = "exportarr_sonarr";
-      exporterConfig = {
-        enable = true;
-        url = "http://127.0.0.1:8989";
-        # testing for real data is tricky, because the api key can not be preconfigured
-        apiKeyFile = pkgs.writeText "dummy-api-key" "eccff6a992bc2e4b88e46d064b26bb4e";
-      };
-      exporterTest = ''
-        wait_for_unit("prometheus-exportarr-sonarr-exporter.service")
-        wait_for_open_port(9707)
-        succeed("curl -sSf 'http://localhost:9707/metrics")
-      '';
-    };
-
     fastly = {
       exporterConfig = {
         enable = true;
@@ -957,31 +942,6 @@ let
       '';
     };
 
-    openvpn = {
-      exporterConfig = {
-        enable = true;
-        group = "openvpn";
-        statusPaths = [ "/run/openvpn-test" ];
-      };
-      metricProvider = {
-        users.groups.openvpn = { };
-        services.openvpn.servers.test = {
-          config = ''
-            dev tun
-            status /run/openvpn-test
-            status-version 3
-          '';
-          up = "chmod g+r /run/openvpn-test";
-        };
-        systemd.services."openvpn-test".serviceConfig.Group = "openvpn";
-      };
-      exporterTest = ''
-        wait_for_unit("openvpn-test.service")
-        wait_for_unit("prometheus-openvpn-exporter.service")
-        succeed("curl -sSf http://localhost:9176/metrics | grep 'openvpn_up{.*} 1'")
-      '';
-    };
-
     pgbouncer = {
       exporterConfig = {
         enable = true;
@@ -1217,6 +1177,39 @@ let
       '';
     };
 
+    restic =
+      let
+        repository = "rest:http://127.0.0.1:8000";
+        passwordFile = pkgs.writeText "restic-test-password" "test-password";
+      in
+      {
+        exporterConfig = {
+          enable = true;
+          inherit repository passwordFile;
+        };
+        metricProvider = {
+          services.restic.server = {
+            enable = true;
+            extraFlags = [ "--no-auth" ];
+          };
+          environment.systemPackages = [ pkgs.restic ];
+        };
+        exporterTest = ''
+          # prometheus-restic-exporter.service fails without initialised repository
+          systemctl("stop prometheus-restic-exporter.service")
+
+          # Initialise the repository
+          wait_for_unit("restic-rest-server.service")
+          wait_for_open_port(8000)
+          succeed("restic init --repo ${repository} --password-file ${passwordFile}")
+
+          systemctl("start prometheus-restic-exporter.service")
+          wait_for_unit("prometheus-restic-exporter.service")
+          wait_for_open_port(9753)
+          wait_until_succeeds("curl -sSf localhost:9753/metrics | grep 'restic_check_success 1.0'")
+        '';
+      };
+
     rspamd = {
       exporterConfig = {
         enable = true;
@@ -1724,7 +1717,12 @@ mapAttrs
       testScript = ''
         ${nodeName}.start()
         ${concatStringsSep "\n" (map (line:
-          if (builtins.substring 0 1 line == " " || builtins.substring 0 1 line == ")")
+          if builtins.any (b: b) [
+            (builtins.match "^[[:space:]]*$" line != null)
+            (builtins.substring 0 1 line == "#")
+            (builtins.substring 0 1 line == " ")
+            (builtins.substring 0 1 line == ")")
+          ]
           then line
           else "${nodeName}.${line}"
         ) (splitString "\n" (removeSuffix "\n" testConfig.exporterTest)))}
diff --git a/nixpkgs/nixos/tests/pyload.nix b/nixpkgs/nixos/tests/pyload.nix
new file mode 100644
index 000000000000..f913e822b2ff
--- /dev/null
+++ b/nixpkgs/nixos/tests/pyload.nix
@@ -0,0 +1,33 @@
+import ./make-test-python.nix ({ lib, ... }: {
+  name = "pyload";
+  meta.maintainers = with lib.maintainers; [ ambroisie ];
+
+  nodes = {
+    machine = { ... }: {
+      services.pyload = {
+        enable = true;
+
+        listenAddress = "0.0.0.0";
+        port = 9876;
+      };
+
+      networking.firewall.allowedTCPPorts = [ 9876 ];
+    };
+
+    client = { };
+  };
+
+  testScript = ''
+    start_all()
+
+    machine.wait_for_unit("pyload.service")
+
+    with subtest("Web interface accessible locally"):
+        machine.wait_until_succeeds("curl -fs localhost:9876")
+
+    client.wait_for_unit("network.target")
+
+    with subtest("Web interface accessible from a different machine"):
+        client.wait_until_succeeds("curl -fs machine:9876")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/qemu-vm-restrictnetwork.nix b/nixpkgs/nixos/tests/qemu-vm-restrictnetwork.nix
index 49a105ef1076..49aefcc099bd 100644
--- a/nixpkgs/nixos/tests/qemu-vm-restrictnetwork.nix
+++ b/nixpkgs/nixos/tests/qemu-vm-restrictnetwork.nix
@@ -21,6 +21,8 @@ import ./make-test-python.nix ({
 
     else:
       start_all()
+      unrestricted.systemctl("start network-online.target")
+      restricted.systemctl("start network-online.target")
       unrestricted.wait_for_unit("network-online.target")
       restricted.wait_for_unit("network-online.target")
 
diff --git a/nixpkgs/nixos/tests/rss2email.nix b/nixpkgs/nixos/tests/rss2email.nix
index f32326feb50f..60b27b95fabe 100644
--- a/nixpkgs/nixos/tests/rss2email.nix
+++ b/nixpkgs/nixos/tests/rss2email.nix
@@ -55,6 +55,7 @@ import ./make-test-python.nix {
   testScript = ''
     start_all()
 
+    server.systemctl("start network-online.target")
     server.wait_for_unit("network-online.target")
     server.wait_for_unit("opensmtpd")
     server.wait_for_unit("dovecot2")
diff --git a/nixpkgs/nixos/tests/sane.nix b/nixpkgs/nixos/tests/sane.nix
new file mode 100644
index 000000000000..cba1b4d1dc4d
--- /dev/null
+++ b/nixpkgs/nixos/tests/sane.nix
@@ -0,0 +1,85 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+/*
+  SANE NixOS test
+  ===============
+  SANE is intrisically tied to hardware, so testing it is not straightforward.
+  However:
+  - a fake webcam can be created with v4l2loopback
+  - sane has a backend (v4l) to use a webcam as a scanner
+  This test creates a webcam /dev/video0, streams a still image with some text
+  through this webcam, uses SANE to scan from the webcam, and uses OCR to check
+  that the expected text was scanned.
+*/
+let
+  text = "66263666188646651519653683416";
+  fontsConf = pkgs.makeFontsConf {
+    fontDirectories = [
+      pkgs.dejavu_fonts.minimal
+    ];
+  };
+  # an image with black on white text spelling "${text}"
+  # for some reason, the test fails if it's jpg instead of png
+  # the font is quite large to make OCR easier
+  image = pkgs.runCommand "image.png"
+    {
+      # only imagemagickBig can render text
+      nativeBuildInputs = [ pkgs.imagemagickBig ];
+      FONTCONFIG_FILE = fontsConf;
+    } ''
+    magick -pointsize 100 label:${text} $out
+  '';
+in
+{
+  name = "sane";
+  nodes.machine = { pkgs, config, ... }: {
+    boot = {
+      # create /dev/video0 as a fake webcam whose content is filled by ffmpeg
+      extraModprobeConfig = ''
+        options v4l2loopback devices=1 max_buffers=2 exclusive_caps=1 card_label=VirtualCam
+      '';
+      kernelModules = [ "v4l2loopback" ];
+      extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ];
+    };
+    systemd.services.fake-webcam = {
+      wantedBy = [ "multi-user.target" ];
+      description = "fill /dev/video0 with ${image}";
+      /* HACK: /dev/video0 is a v4l2 only device, it misses one single v4l1
+      ioctl, VIDIOCSPICT. But sane only supports v4l1, so it will log that this
+      ioctl failed, and assume that the pixel format is Y8 (gray). So we tell
+      ffmpeg to produce this pixel format.
+      */
+      serviceConfig.ExecStart = [ "${pkgs.ffmpeg}/bin/ffmpeg -framerate 30 -re -stream_loop -1 -i ${image} -f v4l2 -pix_fmt gray /dev/video0" ];
+    };
+    hardware.sane.enable = true;
+    system.extraDependencies = [ image ];
+    environment.systemPackages = [
+      pkgs.fswebcam
+      pkgs.tesseract
+      pkgs.v4l-utils
+    ];
+    environment.variables.SANE_DEBUG_V4L = "128";
+  };
+  testScript = ''
+    start_all()
+    machine.wait_for_unit("fake-webcam.service")
+
+    # the device only appears when ffmpeg starts producing frames
+    machine.wait_until_succeeds("scanimage -L | grep /dev/video0")
+
+    machine.succeed("scanimage -L >&2")
+
+    with subtest("debugging: /dev/video0 works"):
+      machine.succeed("v4l2-ctl --all >&2")
+      machine.succeed("fswebcam --no-banner /tmp/webcam.jpg")
+      machine.copy_from_vm("/tmp/webcam.jpg", "webcam")
+
+    # scan with the webcam
+    machine.succeed("scanimage -o /tmp/scan.png >&2")
+    machine.copy_from_vm("/tmp/scan.png", "scan")
+
+    # the image should contain "${text}"
+    output = machine.succeed("tesseract /tmp/scan.png -")
+    print(output)
+    assert "${text}" in output, f"expected text ${text} was not found, OCR found {output!r}"
+  '';
+})
diff --git a/nixpkgs/nixos/tests/ssh-audit.nix b/nixpkgs/nixos/tests/ssh-audit.nix
index bd6255b8044d..25772aba3ea0 100644
--- a/nixpkgs/nixos/tests/ssh-audit.nix
+++ b/nixpkgs/nixos/tests/ssh-audit.nix
@@ -70,6 +70,7 @@ import ./make-test-python.nix (
       ${serverName}.succeed("${pkgs.ssh-audit}/bin/ssh-audit 127.0.0.1")
 
       # Wait for client to be able to connect to the server
+      ${clientName}.systemctl("start network-online.target")
       ${clientName}.wait_for_unit("network-online.target")
 
       # Set up trusted private key
diff --git a/nixpkgs/nixos/tests/suwayomi-server.nix b/nixpkgs/nixos/tests/suwayomi-server.nix
new file mode 100644
index 000000000000..36072028380b
--- /dev/null
+++ b/nixpkgs/nixos/tests/suwayomi-server.nix
@@ -0,0 +1,46 @@
+{ system ? builtins.currentSystem
+, pkgs
+, lib ? pkgs.lib
+}:
+let
+  inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
+  inherit (lib) recursiveUpdate;
+
+  baseTestConfig = {
+    meta.maintainers = with lib.maintainers; [ ratcornu ];
+    nodes.machine = { pkgs, ... }: {
+      services.suwayomi-server = {
+        enable = true;
+        settings.server.port = 1234;
+      };
+    };
+    testScript = ''
+      machine.wait_for_unit("suwayomi-server.service")
+      machine.wait_for_open_port(1234)
+      machine.succeed("curl --fail http://localhost:1234/")
+    '';
+  };
+in
+
+{
+  without-auth = makeTest (recursiveUpdate baseTestConfig {
+    name = "suwayomi-server-without-auth";
+  });
+
+  with-auth = makeTest (recursiveUpdate baseTestConfig {
+    name = "suwayomi-server-with-auth";
+
+    nodes.machine = { pkgs, ... }: {
+      services.suwayomi-server = {
+        enable = true;
+
+        settings.server = {
+          port = 1234;
+          basicAuthEnabled = true;
+          basicAuthUsername = "alice";
+          basicAuthPasswordFile = pkgs.writeText "snakeoil-pass.txt" "pass";
+        };
+      };
+    };
+  });
+}
diff --git a/nixpkgs/nixos/tests/systemd-lock-handler.nix b/nixpkgs/nixos/tests/systemd-lock-handler.nix
new file mode 100644
index 000000000000..d6fb8f545900
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-lock-handler.nix
@@ -0,0 +1,56 @@
+{ lib, ... }: {
+  name = "systemd-lock-handler";
+
+  meta.maintainers = with lib.maintainers; [ liff ];
+
+  enableOCR = true;
+
+  nodes.machine = { config, pkgs, lib, ... }:
+    let
+      touch = "${lib.getBin pkgs.coreutils}/bin/touch";
+    in
+    {
+      imports = [ common/wayland-cage.nix ];
+
+      services.systemd-lock-handler.enable = true;
+
+      systemd.user.services = {
+        test-lock = {
+          partOf = [ "lock.target" ];
+          onSuccess = [ "unlock.target" ];
+          before = [ "lock.target" ];
+          wantedBy = [ "lock.target" ];
+          serviceConfig.ExecStart = "${touch} /tmp/lock.target.activated";
+        };
+        test-unlock = {
+          partOf = [ "unlock.target" ];
+          after = [ "unlock.target" ];
+          wantedBy = [ "unlock.target" ];
+          serviceConfig.ExecStart = "${touch} /tmp/unlock.target.activated";
+        };
+        test-sleep = {
+          partOf = [ "sleep.target" ];
+          before = [ "sleep.target" ];
+          wantedBy = [ "sleep.target" ];
+          serviceConfig.ExecStart = "${touch} /tmp/sleep.target.activated";
+        };
+      };
+    };
+
+  testScript = ''
+    machine.wait_for_unit('graphical.target')
+    machine.wait_for_text('alice@machine')
+
+    machine.send_chars('loginctl lock-session\n')
+    machine.wait_for_file('/tmp/lock.target.activated')
+    machine.wait_for_file('/tmp/unlock.target.activated')
+
+    machine.send_chars('systemctl suspend\n')
+    # wait_for_file won’t complete before the machine is asleep,
+    # so we’ll watch the log instead.
+    machine.wait_for_console_text('Started test-sleep.service.')
+
+    # The VM is asleep, regular shutdown won’t work.
+    machine.crash()
+  '';
+}
diff --git a/nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix b/nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix
index cf0ccb744211..665d8b5a0529 100644
--- a/nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix
+++ b/nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix
@@ -101,6 +101,9 @@ import ./make-test-python.nix ({pkgs, ...}: {
   };
   testScript = { ... }: ''
     start_all()
+
+    router.systemctl("start network-online.target")
+    client.systemctl("start network-online.target")
     router.wait_for_unit("systemd-networkd-wait-online.service")
     client.wait_for_unit("systemd-networkd-wait-online.service")
     client.wait_until_succeeds("ping -c 5 10.0.2.1")
diff --git a/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix b/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
index 54f371e6c070..1e55341657bd 100644
--- a/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
+++ b/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
@@ -263,9 +263,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
           };
         };
       };
-
-      # make the network-online target a requirement, we wait for it in our test script
-      systemd.targets.network-online.wantedBy = [ "multi-user.target" ];
     };
 
     # This is the client behind the router. We should be receiving router
@@ -278,9 +275,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
         useNetworkd = true;
         useDHCP = false;
       };
-
-      # make the network-online target a requirement, we wait for it in our test script
-      systemd.targets.network-online.wantedBy = [ "multi-user.target" ];
     };
   };
 
@@ -294,6 +288,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     # Since we only care about IPv6 that should not involve waiting for legacy
     # IP leases.
     client.start()
+    client.systemctl("start network-online.target")
     client.wait_for_unit("network-online.target")
 
     # the static address on the router should not be reachable
@@ -312,6 +307,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     isp.wait_for_unit("multi-user.target")
 
     # wait until the uplink interface has a good status
+    router.systemctl("start network-online.target")
     router.wait_for_unit("network-online.target")
     router.wait_until_succeeds("ping -6 -c1 2001:DB8::1")
 
diff --git a/nixpkgs/nixos/tests/systemd-nspawn.nix b/nixpkgs/nixos/tests/systemd-nspawn.nix
index 1a4251ef069e..b86762233d18 100644
--- a/nixpkgs/nixos/tests/systemd-nspawn.nix
+++ b/nixpkgs/nixos/tests/systemd-nspawn.nix
@@ -38,6 +38,7 @@ in {
     start_all()
 
     server.wait_for_unit("nginx.service")
+    client.systemctl("start network-online.target")
     client.wait_for_unit("network-online.target")
     client.succeed("machinectl pull-raw --verify=signature http://server/testimage.raw")
     client.succeed(
diff --git a/nixpkgs/nixos/tests/systemd-sysupdate.nix b/nixpkgs/nixos/tests/systemd-sysupdate.nix
index 37811605dbb2..6592764c9ff4 100644
--- a/nixpkgs/nixos/tests/systemd-sysupdate.nix
+++ b/nixpkgs/nixos/tests/systemd-sysupdate.nix
@@ -23,8 +23,8 @@ in
             mkdir -p $out
             cd $out
 
-            echo "nixos" > nixos_1.efi
-            sha256sum nixos_1.efi > SHA256SUMS
+            echo "nixos" > nixos_1.txt
+            sha256sum nixos_1.txt > SHA256SUMS
 
             export GNUPGHOME="$(mktemp -d)"
             cp -R ${gpgKeyring}/* $GNUPGHOME
@@ -39,15 +39,15 @@ in
       systemd.sysupdate = {
         enable = true;
         transfers = {
-          "uki" = {
+          "text-file" = {
             Source = {
               Type = "url-file";
               Path = "http://server/";
-              MatchPattern = "nixos_@v.efi";
+              MatchPattern = "nixos_@v.txt";
             };
             Target = {
-              Path = "/boot/EFI/Linux";
-              MatchPattern = "nixos_@v.efi";
+              Path = "/";
+              MatchPattern = [ "nixos_@v.txt" ];
             };
           };
         };
@@ -61,6 +61,6 @@ in
     server.wait_for_unit("nginx.service")
 
     target.succeed("systemctl start systemd-sysupdate")
-    assert "nixos" in target.wait_until_succeeds("cat /boot/EFI/Linux/nixos_1.efi", timeout=5)
+    assert "nixos" in target.wait_until_succeeds("cat /nixos_1.txt", timeout=5)
   '';
 }
diff --git a/nixpkgs/nixos/tests/systemd-sysusers-immutable.nix b/nixpkgs/nixos/tests/systemd-sysusers-immutable.nix
new file mode 100644
index 000000000000..42cbf84d175e
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-sysusers-immutable.nix
@@ -0,0 +1,64 @@
+{ lib, ... }:
+
+let
+  rootPassword = "$y$j9T$p6OI0WN7.rSfZBOijjRdR.$xUOA2MTcB48ac.9Oc5fz8cxwLv1mMqabnn333iOzSA6";
+  normaloPassword = "$y$j9T$3aiOV/8CADAK22OK2QT3/0$67OKd50Z4qTaZ8c/eRWHLIM.o3ujtC1.n9ysmJfv639";
+  newNormaloPassword = "mellow";
+in
+
+{
+
+  name = "activation-sysusers-immutable";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes.machine = {
+    systemd.sysusers.enable = true;
+    users.mutableUsers = false;
+
+    # Override the empty root password set by the test instrumentation
+    users.users.root.hashedPasswordFile = lib.mkForce null;
+    users.users.root.initialHashedPassword = rootPassword;
+    users.users.normalo = {
+      isNormalUser = true;
+      initialHashedPassword = normaloPassword;
+    };
+
+    specialisation.new-generation.configuration = {
+      users.users.new-normalo = {
+        isNormalUser = true;
+        initialPassword = newNormaloPassword;
+      };
+    };
+  };
+
+  testScript = ''
+    with subtest("Users are not created with systemd-sysusers"):
+      machine.fail("systemctl status systemd-sysusers.service")
+      machine.fail("ls /etc/sysusers.d")
+
+    with subtest("Correct mode on the password files"):
+      assert machine.succeed("stat -c '%a' /etc/passwd") == "644\n"
+      assert machine.succeed("stat -c '%a' /etc/group") == "644\n"
+      assert machine.succeed("stat -c '%a' /etc/shadow") == "0\n"
+      assert machine.succeed("stat -c '%a' /etc/gshadow") == "0\n"
+
+    with subtest("root user has correct password"):
+      print(machine.succeed("getent passwd root"))
+      assert "${rootPassword}" in machine.succeed("getent shadow root"), "root user password is not correct"
+
+    with subtest("normalo user is created"):
+      print(machine.succeed("getent passwd normalo"))
+      assert machine.succeed("stat -c '%U' /home/normalo") == "normalo\n"
+      assert "${normaloPassword}" in machine.succeed("getent shadow normalo"), "normalo user password is not correct"
+
+
+    machine.succeed("/run/current-system/specialisation/new-generation/bin/switch-to-configuration switch")
+
+
+    with subtest("new-normalo user is created after switching to new generation"):
+      print(machine.succeed("getent passwd new-normalo"))
+      print(machine.succeed("getent shadow new-normalo"))
+      assert machine.succeed("stat -c '%U' /home/new-normalo") == "new-normalo\n"
+  '';
+}
diff --git a/nixpkgs/nixos/tests/systemd-sysusers-mutable.nix b/nixpkgs/nixos/tests/systemd-sysusers-mutable.nix
new file mode 100644
index 000000000000..e69cfe23a59a
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-sysusers-mutable.nix
@@ -0,0 +1,71 @@
+{ lib, ... }:
+
+let
+  rootPassword = "$y$j9T$p6OI0WN7.rSfZBOijjRdR.$xUOA2MTcB48ac.9Oc5fz8cxwLv1mMqabnn333iOzSA6";
+  normaloPassword = "hello";
+  newNormaloPassword = "$y$j9T$p6OI0WN7.rSfZBOijjRdR.$xUOA2MTcB48ac.9Oc5fz8cxwLv1mMqabnn333iOzSA6";
+in
+
+{
+
+  name = "activation-sysusers-mutable";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes.machine = { pkgs, ... }: {
+    systemd.sysusers.enable = true;
+    users.mutableUsers = true;
+
+    # Prerequisites
+    system.etc.overlay.enable = true;
+    boot.initrd.systemd.enable = true;
+    boot.kernelPackages = pkgs.linuxPackages_latest;
+
+    # Override the empty root password set by the test instrumentation
+    users.users.root.hashedPasswordFile = lib.mkForce null;
+    users.users.root.initialHashedPassword = rootPassword;
+    users.users.normalo = {
+      isNormalUser = true;
+      initialPassword = normaloPassword;
+    };
+
+    specialisation.new-generation.configuration = {
+      users.users.new-normalo = {
+        isNormalUser = true;
+        initialHashedPassword = newNormaloPassword;
+      };
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("systemd-sysusers.service")
+
+    with subtest("systemd-sysusers.service contains the credentials"):
+      sysusers_service = machine.succeed("systemctl cat systemd-sysusers.service")
+      print(sysusers_service)
+      assert "SetCredential=passwd.plaintext-password.normalo:${normaloPassword}" in sysusers_service
+
+    with subtest("Correct mode on the password files"):
+      assert machine.succeed("stat -c '%a' /etc/passwd") == "644\n"
+      assert machine.succeed("stat -c '%a' /etc/group") == "644\n"
+      assert machine.succeed("stat -c '%a' /etc/shadow") == "0\n"
+      assert machine.succeed("stat -c '%a' /etc/gshadow") == "0\n"
+
+    with subtest("root user has correct password"):
+      print(machine.succeed("getent passwd root"))
+      assert "${rootPassword}" in machine.succeed("getent shadow root"), "root user password is not correct"
+
+    with subtest("normalo user is created"):
+      print(machine.succeed("getent passwd normalo"))
+      assert machine.succeed("stat -c '%U' /home/normalo") == "normalo\n"
+
+
+    machine.succeed("/run/current-system/specialisation/new-generation/bin/switch-to-configuration switch")
+
+
+    with subtest("new-normalo user is created after switching to new generation"):
+      print(machine.succeed("getent passwd new-normalo"))
+      assert machine.succeed("stat -c '%U' /home/new-normalo") == "new-normalo\n"
+      assert "${newNormaloPassword}" in machine.succeed("getent shadow new-normalo"), "new-normalo user password is not correct"
+  '';
+}
diff --git a/nixpkgs/nixos/tests/tayga.nix b/nixpkgs/nixos/tests/tayga.nix
index 44974f6efea8..4aade67d74d0 100644
--- a/nixpkgs/nixos/tests/tayga.nix
+++ b/nixpkgs/nixos/tests/tayga.nix
@@ -206,6 +206,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
   testScript = ''
     # start client and server
     for machine in client, server:
+      machine.systemctl("start network-online.target")
       machine.wait_for_unit("network-online.target")
       machine.log(machine.execute("ip addr")[1])
       machine.log(machine.execute("ip route")[1])
@@ -214,6 +215,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
     # test systemd-networkd and nixos-scripts based router
     for router in router_systemd, router_nixos:
       router.start()
+      router.systemctl("start network-online.target")
       router.wait_for_unit("network-online.target")
       router.wait_for_unit("tayga.service")
       router.log(machine.execute("ip addr")[1])
diff --git a/nixpkgs/nixos/tests/trafficserver.nix b/nixpkgs/nixos/tests/trafficserver.nix
index e4557c6c50e5..94d0e4dd926e 100644
--- a/nixpkgs/nixos/tests/trafficserver.nix
+++ b/nixpkgs/nixos/tests/trafficserver.nix
@@ -104,6 +104,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     ats.wait_for_open_port(80)
     httpbin.wait_for_unit("httpbin")
     httpbin.wait_for_open_port(80)
+    client.systemctl("start network-online.target")
     client.wait_for_unit("network-online.target")
 
     with subtest("Traffic Server is running"):
diff --git a/nixpkgs/nixos/tests/tsm-client-gui.nix b/nixpkgs/nixos/tests/tsm-client-gui.nix
index c9632546db6e..ca10cddc411f 100644
--- a/nixpkgs/nixos/tests/tsm-client-gui.nix
+++ b/nixpkgs/nixos/tests/tsm-client-gui.nix
@@ -31,7 +31,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
     machine.execute("DSM_LOG=/tmp dsmj -optfile=/dev/null >&2 &")
 
     # does it report the "TCP/IP connection failure" error code?
-    machine.wait_for_window("IBM Spectrum Protect")
+    machine.wait_for_window("IBM Storage Protect")
     machine.wait_for_text("ANS2610S")
     machine.send_key("esc")
 
diff --git a/nixpkgs/nixos/tests/ulogd/ulogd.py b/nixpkgs/nixos/tests/ulogd/ulogd.py
index d20daa4d733a..76a8d0c6e24a 100644
--- a/nixpkgs/nixos/tests/ulogd/ulogd.py
+++ b/nixpkgs/nixos/tests/ulogd/ulogd.py
@@ -1,5 +1,6 @@
 start_all()
 machine.wait_for_unit("ulogd.service")
+machine.systemctl("start network-online.target")
 machine.wait_for_unit("network-online.target")
 
 with subtest("Ulogd is running"):
diff --git a/nixpkgs/nixos/tests/upnp.nix b/nixpkgs/nixos/tests/upnp.nix
index 5e135267403b..93bc08f752ce 100644
--- a/nixpkgs/nixos/tests/upnp.nix
+++ b/nixpkgs/nixos/tests/upnp.nix
@@ -81,11 +81,13 @@ in
       start_all()
 
       # Wait for network and miniupnpd.
+      router.systemctl("start network-online.target")
       router.wait_for_unit("network-online.target")
       # $router.wait_for_unit("nat")
       router.wait_for_unit("${if useNftables then "nftables" else "firewall"}.service")
       router.wait_for_unit("miniupnpd")
 
+      client1.systemctl("start network-online.target")
       client1.wait_for_unit("network-online.target")
 
       client1.succeed("upnpc -a ${internalClient1Address} 9000 9000 TCP")
diff --git a/nixpkgs/nixos/tests/uptermd.nix b/nixpkgs/nixos/tests/uptermd.nix
index 429e3c9dd5ff..469aa5047c27 100644
--- a/nixpkgs/nixos/tests/uptermd.nix
+++ b/nixpkgs/nixos/tests/uptermd.nix
@@ -28,6 +28,7 @@ in
     start_all()
 
     server.wait_for_unit("uptermd.service")
+    server.systemctl("start network-online.target")
     server.wait_for_unit("network-online.target")
 
     # wait for upterm port to be reachable
diff --git a/nixpkgs/nixos/tests/urn-timer.nix b/nixpkgs/nixos/tests/urn-timer.nix
new file mode 100644
index 000000000000..10c5bef49b5b
--- /dev/null
+++ b/nixpkgs/nixos/tests/urn-timer.nix
@@ -0,0 +1,26 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "urn-timer";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ fgaz ];
+  };
+
+  nodes.machine = { config, pkgs, ... }: {
+    imports = [
+      ./common/x11.nix
+    ];
+
+    services.xserver.enable = true;
+    environment.systemPackages = [ pkgs.urn-timer ];
+  };
+
+  enableOCR = true;
+
+  testScript =
+    ''
+      machine.wait_for_x()
+      machine.execute("urn-gtk ${pkgs.urn-timer.src}/splits_examples/sotn.json >&2 &")
+      machine.wait_for_window("urn")
+      machine.wait_for_text(r"(Mist|Bat|Reverse|Dracula)")
+      machine.screenshot("screen")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/watchdogd.nix b/nixpkgs/nixos/tests/watchdogd.nix
new file mode 100644
index 000000000000..663e97cbae10
--- /dev/null
+++ b/nixpkgs/nixos/tests/watchdogd.nix
@@ -0,0 +1,22 @@
+import ./make-test-python.nix ({ lib, ... }: {
+  name = "watchdogd";
+  meta.maintainers = with lib.maintainers; [ vifino ];
+
+  nodes.machine = { pkgs, ... }: {
+    virtualisation.qemu.options = [
+      "-device i6300esb" # virtual watchdog timer
+    ];
+    boot.kernelModules = [ "i6300esb" ];
+    services.watchdogd.enable = true;
+    services.watchdogd.settings = {
+      supervisor.enabled = true;
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("watchdogd.service")
+
+    assert "i6300ESB" in machine.succeed("watchdogctl status")
+    machine.succeed("watchdogctl test")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/web-apps/netbox-upgrade.nix b/nixpkgs/nixos/tests/web-apps/netbox-upgrade.nix
index b5403eb678bc..4c554e7ae613 100644
--- a/nixpkgs/nixos/tests/web-apps/netbox-upgrade.nix
+++ b/nixpkgs/nixos/tests/web-apps/netbox-upgrade.nix
@@ -1,6 +1,6 @@
 import ../make-test-python.nix ({ lib, pkgs, ... }: let
-  oldNetbox = pkgs.netbox_3_5;
-  newNetbox = pkgs.netbox_3_6;
+  oldNetbox = pkgs.netbox_3_6;
+  newNetbox = pkgs.netbox_3_7;
 in {
   name = "netbox-upgrade";
 
diff --git a/nixpkgs/nixos/tests/web-apps/pretalx.nix b/nixpkgs/nixos/tests/web-apps/pretalx.nix
new file mode 100644
index 000000000000..a226639b076b
--- /dev/null
+++ b/nixpkgs/nixos/tests/web-apps/pretalx.nix
@@ -0,0 +1,31 @@
+{ lib, ... }:
+
+{
+  name = "pretalx";
+  meta.maintainers = lib.teams.c3d2.members;
+
+  nodes = {
+    pretalx = {
+      networking.extraHosts = ''
+        127.0.0.1 talks.local
+      '';
+
+      services.pretalx = {
+        enable = true;
+        nginx.domain = "talks.local";
+        settings = {
+          site.url = "http://talks.local";
+        };
+      };
+    };
+  };
+
+  testScript = ''
+    start_all()
+
+    pretalx.wait_for_unit("pretalx-web.service")
+    pretalx.wait_for_unit("pretalx-worker.service")
+
+    pretalx.wait_until_succeeds("curl -q --fail http://talks.local/orga/")
+  '';
+}
diff --git a/nixpkgs/nixos/tests/web-servers/stargazer.nix b/nixpkgs/nixos/tests/web-servers/stargazer.nix
index 6365d6a4fff1..f56d1b8c9454 100644
--- a/nixpkgs/nixos/tests/web-servers/stargazer.nix
+++ b/nixpkgs/nixos/tests/web-servers/stargazer.nix
@@ -1,4 +1,41 @@
 { pkgs, lib, ... }:
+let
+  test_script = pkgs.stdenv.mkDerivation rec {
+    pname = "stargazer-test-script";
+    inherit (pkgs.stargazer) version src;
+    buildInputs = with pkgs; [ (python3.withPackages (ps: with ps; [ cryptography ])) ];
+    dontBuild = true;
+    doCheck = false;
+    installPhase = ''
+      mkdir -p $out/bin
+      cp scripts/gemini-diagnostics $out/bin/test
+    '';
+  };
+  test_env = pkgs.stdenv.mkDerivation rec {
+    pname = "stargazer-test-env";
+    inherit (pkgs.stargazer) version src;
+    buildPhase = ''
+      cc test_data/cgi-bin/loop.c -o test_data/cgi-bin/loop
+    '';
+    doCheck = false;
+    installPhase = ''
+      mkdir -p $out
+      cp -r * $out/
+    '';
+  };
+  scgi_server = pkgs.stdenv.mkDerivation rec {
+    pname = "stargazer-test-scgi-server";
+    inherit (pkgs.stargazer) version src;
+    buildInputs = with pkgs; [ python3 ];
+    dontConfigure = true;
+    dontBuild = true;
+    doCheck = false;
+    installPhase = ''
+      mkdir -p $out/bin
+      cp scripts/scgi-server $out/bin/scgi-server
+    '';
+  };
+in
 {
   name = "stargazer";
   meta = with lib.maintainers; { maintainers = [ gaykitty ]; };
@@ -7,25 +44,84 @@
     geminiserver = { pkgs, ... }: {
       services.stargazer = {
         enable = true;
+        connectionLogging = false;
+        requestTimeout = 1;
         routes = [
           {
             route = "localhost";
-            root = toString (pkgs.writeTextDir "index.gmi" ''
-              # Hello NixOS!
-            '');
+            root = "${test_env}/test_data/test_site";
+          }
+          {
+            route = "localhost=/en.gmi";
+            root = "${test_env}/test_data/test_site";
+            lang = "en";
+            charset = "ascii";
+          }
+          {
+            route = "localhost~/(.*).gemini";
+            root = "${test_env}/test_data/test_site";
+            rewrite = "\\1.gmi";
+            lang = "en";
+            charset = "ascii";
+          }
+          {
+            route = "localhost=/plain.txt";
+            root = "${test_env}/test_data/test_site";
+            lang = "en";
+            charset = "ascii";
+            cert-path = "/var/lib/gemini/certs/localhost.crt";
+            key-path = "/var/lib/gemini/certs/localhost.key";
+          }
+          {
+            route = "localhost:/cgi-bin";
+            root = "${test_env}/test_data";
+            cgi = true;
+            cgi-timeout = 5;
+          }
+          {
+            route = "localhost:/scgi";
+            scgi = true;
+            scgi-address = "127.0.0.1:1099";
+          }
+          {
+            route = "localhost=/root";
+            redirect = "..";
+            permanent = true;
+          }
+          {
+            route = "localhost=/priv.gmi";
+            root = "${test_env}/test_data/test_site";
+            client-cert = "${test_env}/test_data/client_cert/good.crt";
+          }
+          {
+            route = "example.com~(.*)";
+            redirect = "gemini://localhost";
+            rewrite = "\\1";
+          }
+          {
+            route = "localhost:/no-exist";
+            root = "./does_not_exist";
           }
         ];
       };
+      systemd.services.scgi_server = {
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          ExecStart = "${scgi_server}/bin/scgi-server";
+        };
+      };
     };
   };
 
   testScript = { nodes, ... }: ''
+    geminiserver.wait_for_unit("scgi_server")
+    geminiserver.wait_for_open_port(1099)
     geminiserver.wait_for_unit("stargazer")
     geminiserver.wait_for_open_port(1965)
 
-    with subtest("check is serving over gemini"):
-      response = geminiserver.succeed("${pkgs.gemget}/bin/gemget --header -o - gemini://localhost:1965")
+    with subtest("stargazer test suite"):
+      response = geminiserver.succeed("sh -c 'cd ${test_env}; ${test_script}/bin/test'")
       print(response)
-      assert "Hello NixOS!" in response
   '';
 }
diff --git a/nixpkgs/nixos/tests/web-servers/ttyd.nix b/nixpkgs/nixos/tests/web-servers/ttyd.nix
new file mode 100644
index 000000000000..d161673684b3
--- /dev/null
+++ b/nixpkgs/nixos/tests/web-servers/ttyd.nix
@@ -0,0 +1,19 @@
+import ../make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "ttyd";
+  meta.maintainers = with lib.maintainers; [ stunkymonkey ];
+
+  nodes.machine = { pkgs, ... }: {
+    services.ttyd = {
+      enable = true;
+      username = "foo";
+      passwordFile = pkgs.writeText "password" "bar";
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("ttyd.service")
+    machine.wait_for_open_port(7681)
+    response = machine.succeed("curl -vvv -u foo:bar -s -H 'Host: ttyd' http://127.0.0.1:7681/")
+    assert '<title>ttyd - Terminal</title>' in response, "Page didn't load successfully"
+  '';
+})
diff --git a/nixpkgs/nixos/tests/zfs.nix b/nixpkgs/nixos/tests/zfs.nix
index 8fedcf095af6..0b411b0b9d8a 100644
--- a/nixpkgs/nixos/tests/zfs.nix
+++ b/nixpkgs/nixos/tests/zfs.nix
@@ -8,12 +8,9 @@ with import ../lib/testing-python.nix { inherit system pkgs; };
 let
 
   makeZfsTest = name:
-    { kernelPackage ? if enableUnstable
-                      then pkgs.zfsUnstable.latestCompatibleLinuxPackages
-                      else pkgs.linuxPackages
-    , enableUnstable ? false
+    { kernelPackages
     , enableSystemdStage1 ? false
-    , zfsPackage ? if enableUnstable then pkgs.zfs else pkgs.zfsUnstable
+    , zfsPackage
     , extraTest ? ""
     }:
     makeTest {
@@ -35,7 +32,7 @@ let
         boot.loader.timeout = 0;
         boot.loader.efi.canTouchEfiVariables = true;
         networking.hostId = "deadbeef";
-        boot.kernelPackages = kernelPackage;
+        boot.kernelPackages = kernelPackages;
         boot.zfs.package = zfsPackage;
         boot.supportedFilesystems = [ "zfs" ];
         boot.initrd.systemd.enable = enableSystemdStage1;
@@ -197,16 +194,22 @@ in {
   # maintainer: @raitobezarius
   series_2_1 = makeZfsTest "2.1-series" {
     zfsPackage = pkgs.zfs_2_1;
+    kernelPackages = pkgs.linuxPackages;
   };
 
-  stable = makeZfsTest "stable" { };
+  stable = makeZfsTest "stable" {
+    zfsPackage = pkgs.zfsStable;
+    kernelPackages = pkgs.linuxPackages;
+  };
 
-  unstable = makeZfsTest "unstable" {
-    enableUnstable = true;
+  unstable = makeZfsTest "unstable" rec {
+    zfsPackage = pkgs.zfsUnstable;
+    kernelPackages = zfsPackage.latestCompatibleLinuxPackages;
   };
 
-  unstableWithSystemdStage1 = makeZfsTest "unstable" {
-    enableUnstable = true;
+  unstableWithSystemdStage1 = makeZfsTest "unstable" rec {
+    zfsPackage = pkgs.zfsUnstable;
+    kernelPackages = zfsPackage.latestCompatibleLinuxPackages;
     enableSystemdStage1 = true;
   };
 
diff --git a/nixpkgs/nixos/tests/zigbee2mqtt.nix b/nixpkgs/nixos/tests/zigbee2mqtt.nix
index 1a40d175df83..9d6d03a4b9bb 100644
--- a/nixpkgs/nixos/tests/zigbee2mqtt.nix
+++ b/nixpkgs/nixos/tests/zigbee2mqtt.nix
@@ -3,6 +3,15 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
     name = "zigbee2mqtt";
     nodes.machine = { pkgs, ... }:
       {
+        systemd.services.dummy-serial = {
+          wantedBy = [
+            "multi-user.target"
+          ];
+          serviceConfig = {
+            ExecStart = "${pkgs.socat}/bin/socat pty,link=/dev/ttyACM0,mode=666 pty,link=/dev/ttyACM1";
+          };
+        };
+
         services.zigbee2mqtt = {
           enable = true;
         };
@@ -11,10 +20,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
       };
 
     testScript = ''
-      machine.wait_for_unit("zigbee2mqtt.service")
+      machine.wait_for_unit("multi-user.target")
       machine.wait_until_fails("systemctl status zigbee2mqtt.service")
       machine.succeed(
-          "journalctl -eu zigbee2mqtt | grep \"Error: Error while opening serialport 'Error: Error: No such file or directory, cannot open /dev/ttyACM0'\""
+          "journalctl -eu zigbee2mqtt | grep 'Failed to connect to the adapter'"
       )
 
       machine.log(machine.succeed("systemd-analyze security zigbee2mqtt.service"))
diff --git a/nixpkgs/nixos/tests/zrepl.nix b/nixpkgs/nixos/tests/zrepl.nix
index b16c7eddc7ae..bdf11122c73f 100644
--- a/nixpkgs/nixos/tests/zrepl.nix
+++ b/nixpkgs/nixos/tests/zrepl.nix
@@ -42,6 +42,7 @@ import ./make-test-python.nix (
       start_all()
 
       with subtest("Wait for zrepl and network ready"):
+          host.systemctl("start network-online.target")
           host.wait_for_unit("network-online.target")
           host.wait_for_unit("zrepl.service")