about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/installation/upgrading.chapter.md16
-rw-r--r--nixos/doc/manual/release-notes/rl-2311.section.md1698
-rw-r--r--nixos/doc/manual/release-notes/rl-2405.section.md3
-rw-r--r--nixos/modules/hardware/ckb-next.nix9
-rw-r--r--nixos/modules/hardware/digitalbitbox.nix9
-rw-r--r--nixos/modules/hardware/opentabletdriver.nix9
-rw-r--r--nixos/modules/misc/locate.nix10
-rw-r--r--nixos/modules/module-list.nix9
-rw-r--r--nixos/modules/programs/atop.nix9
-rw-r--r--nixos/modules/programs/captive-browser.nix10
-rw-r--r--nixos/modules/programs/digitalbitbox/default.nix9
-rw-r--r--nixos/modules/programs/dmrconfig.nix7
-rw-r--r--nixos/modules/programs/evince.nix7
-rw-r--r--nixos/modules/programs/feedbackd.nix9
-rw-r--r--nixos/modules/programs/file-roller.nix7
-rw-r--r--nixos/modules/programs/flexoptix-app.nix7
-rw-r--r--nixos/modules/programs/gamescope.nix9
-rw-r--r--nixos/modules/programs/git.nix15
-rw-r--r--nixos/modules/programs/gnupg.nix9
-rw-r--r--nixos/modules/programs/htop.nix9
-rw-r--r--nixos/modules/programs/i3lock.nix14
-rw-r--r--nixos/modules/programs/java.nix9
-rw-r--r--nixos/modules/programs/k40-whisperer.nix10
-rw-r--r--nixos/modules/programs/kdeconnect.nix10
-rw-r--r--nixos/modules/programs/mininet.nix33
-rw-r--r--nixos/modules/programs/mtr.nix9
-rw-r--r--nixos/modules/programs/neovim.nix7
-rw-r--r--nixos/modules/programs/nix-index.nix7
-rw-r--r--nixos/modules/programs/nncp.nix7
-rw-r--r--nixos/modules/programs/noisetorch.nix9
-rw-r--r--nixos/modules/programs/npm.nix8
-rw-r--r--nixos/modules/programs/proxychains.nix4
-rw-r--r--nixos/modules/programs/singularity.nix10
-rw-r--r--nixos/modules/programs/ssh.nix9
-rw-r--r--nixos/modules/programs/tsm-client.nix13
-rw-r--r--nixos/modules/programs/vim.nix10
-rw-r--r--nixos/modules/programs/wayland/river.nix9
-rw-r--r--nixos/modules/programs/weylus.nix7
-rw-r--r--nixos/modules/programs/wireshark.nix9
-rw-r--r--nixos/modules/programs/xonsh.nix10
-rw-r--r--nixos/modules/programs/zsh/oh-my-zsh.nix10
-rw-r--r--nixos/modules/programs/zsh/zsh-autoenv.nix10
-rw-r--r--nixos/modules/security/please.nix9
-rw-r--r--nixos/modules/services/admin/meshcentral.nix7
-rw-r--r--nixos/modules/services/amqp/rabbitmq.nix9
-rw-r--r--nixos/modules/services/audio/botamusique.nix7
-rw-r--r--nixos/modules/services/audio/jack.nix11
-rw-r--r--nixos/modules/services/audio/jmusicbot.nix7
-rw-r--r--nixos/modules/services/audio/slimserver.nix7
-rw-r--r--nixos/modules/services/backup/postgresql-wal-receiver.nix8
-rw-r--r--nixos/modules/services/backup/restic-rest-server.nix7
-rw-r--r--nixos/modules/services/backup/restic.nix9
-rw-r--r--nixos/modules/services/backup/zrepl.nix7
-rw-r--r--nixos/modules/services/blockchain/ethereum/geth.nix7
-rw-r--r--nixos/modules/services/cluster/corosync/default.nix7
-rw-r--r--nixos/modules/services/cluster/hadoop/default.nix7
-rw-r--r--nixos/modules/services/cluster/hadoop/hbase.nix7
-rw-r--r--nixos/modules/services/cluster/k3s/default.nix7
-rw-r--r--nixos/modules/services/cluster/kubernetes/default.nix7
-rw-r--r--nixos/modules/services/cluster/pacemaker/default.nix7
-rw-r--r--nixos/modules/services/cluster/spark/default.nix24
-rw-r--r--nixos/modules/services/computing/boinc/client.nix10
-rw-r--r--nixos/modules/services/computing/foldingathome/client.nix9
-rw-r--r--nixos/modules/services/computing/slurm/slurm.nix10
-rw-r--r--nixos/modules/services/continuous-integration/buildbot/master.nix8
-rw-r--r--nixos/modules/services/continuous-integration/buildbot/worker.nix8
-rw-r--r--nixos/modules/services/continuous-integration/github-runner/options.nix9
-rw-r--r--nixos/modules/services/continuous-integration/gitlab-runner.nix8
-rw-r--r--nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix11
-rw-r--r--nixos/modules/services/continuous-integration/hydra/default.nix7
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/default.nix7
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/slave.nix9
-rw-r--r--nixos/modules/services/databases/aerospike.nix7
-rw-r--r--nixos/modules/services/databases/cassandra.nix11
-rw-r--r--nixos/modules/services/databases/clickhouse.nix9
-rw-r--r--nixos/modules/services/databases/cockroachdb.nix9
-rw-r--r--nixos/modules/services/databases/couchdb.nix9
-rw-r--r--nixos/modules/services/databases/firebird.nix10
-rw-r--r--nixos/modules/services/databases/hbase-standalone.nix10
-rw-r--r--nixos/modules/services/databases/influxdb.nix7
-rw-r--r--nixos/modules/services/databases/influxdb2.nix8
-rw-r--r--nixos/modules/services/databases/monetdb.nix7
-rw-r--r--nixos/modules/services/databases/mongodb.nix9
-rw-r--r--nixos/modules/services/databases/neo4j.nix9
-rw-r--r--nixos/modules/services/databases/openldap.nix9
-rw-r--r--nixos/modules/services/databases/opentsdb.nix9
-rw-r--r--nixos/modules/services/databases/pgbouncer.nix9
-rw-r--r--nixos/modules/services/databases/pgmanage.nix9
-rw-r--r--nixos/modules/services/databases/postgresql.nix8
-rw-r--r--nixos/modules/services/databases/redis.nix7
-rw-r--r--nixos/modules/services/databases/surrealdb.nix9
-rw-r--r--nixos/modules/services/databases/victoriametrics.nix9
-rw-r--r--nixos/modules/services/desktops/deepin/app-services.nix11
-rw-r--r--nixos/modules/services/desktops/gvfs.nix7
-rw-r--r--nixos/modules/services/desktops/pipewire/pipewire.nix9
-rw-r--r--nixos/modules/services/development/athens.md52
-rw-r--r--nixos/modules/services/development/athens.nix936
-rw-r--r--nixos/modules/services/development/distccd.nix9
-rw-r--r--nixos/modules/services/development/jupyter/default.nix15
-rw-r--r--nixos/modules/services/development/rstudio-server/default.nix10
-rw-r--r--nixos/modules/services/development/zammad.nix7
-rw-r--r--nixos/modules/services/display-managers/greetd.nix7
-rw-r--r--nixos/modules/services/editors/emacs.nix9
-rw-r--r--nixos/modules/services/editors/infinoted.nix9
-rw-r--r--nixos/modules/services/finance/odoo.nix7
-rw-r--r--nixos/modules/services/games/asf.nix25
-rw-r--r--nixos/modules/services/games/crossfire-server.nix12
-rw-r--r--nixos/modules/services/games/deliantra-server.nix12
-rw-r--r--nixos/modules/services/games/factorio.nix10
-rw-r--r--nixos/modules/services/games/mchprs.nix7
-rw-r--r--nixos/modules/services/games/minecraft-server.nix8
-rw-r--r--nixos/modules/services/hardware/bluetooth.nix11
-rw-r--r--nixos/modules/services/hardware/freefall.nix9
-rw-r--r--nixos/modules/services/hardware/fwupd.nix9
-rw-r--r--nixos/modules/services/hardware/joycond.nix9
-rw-r--r--nixos/modules/services/hardware/kanata.nix13
-rw-r--r--nixos/modules/services/hardware/openrgb.nix7
-rw-r--r--nixos/modules/services/hardware/sane.nix11
-rw-r--r--nixos/modules/services/hardware/thermald.nix7
-rw-r--r--nixos/modules/services/hardware/undervolt.nix9
-rw-r--r--nixos/modules/services/hardware/upower.nix9
-rw-r--r--nixos/modules/services/hardware/vdr.nix8
-rw-r--r--nixos/modules/services/home-automation/esphome.nix13
-rw-r--r--nixos/modules/services/home-automation/zigbee2mqtt.nix9
-rw-r--r--nixos/modules/services/logging/SystemdJournal2Gelf.nix9
-rw-r--r--nixos/modules/services/logging/filebeat.nix11
-rw-r--r--nixos/modules/services/logging/fluentd.nix7
-rw-r--r--nixos/modules/services/logging/heartbeat.nix10
-rw-r--r--nixos/modules/services/logging/journalbeat.nix9
-rw-r--r--nixos/modules/services/logging/logstash.nix7
-rw-r--r--nixos/modules/services/logging/syslog-ng.nix9
-rw-r--r--nixos/modules/services/mail/exim.nix10
-rw-r--r--nixos/modules/services/mail/offlineimap.nix7
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix7
-rw-r--r--nixos/modules/services/mail/public-inbox.nix7
-rw-r--r--nixos/modules/services/mail/roundcube.nix15
-rw-r--r--nixos/modules/services/matrix/appservice-discord.nix9
-rw-r--r--nixos/modules/services/matrix/conduit.nix9
-rw-r--r--nixos/modules/services/misc/airsonic.nix11
-rw-r--r--nixos/modules/services/misc/ananicy.nix18
-rw-r--r--nixos/modules/services/misc/ankisyncd.nix7
-rw-r--r--nixos/modules/services/misc/apache-kafka.nix7
-rw-r--r--nixos/modules/services/misc/bcg.nix7
-rw-r--r--nixos/modules/services/misc/cgminer.nix7
-rw-r--r--nixos/modules/services/misc/clipcat.nix7
-rw-r--r--nixos/modules/services/misc/clipmenu.nix7
-rw-r--r--nixos/modules/services/misc/confd.nix7
-rw-r--r--nixos/modules/services/misc/disnix.nix7
-rw-r--r--nixos/modules/services/misc/docker-registry.nix8
-rw-r--r--nixos/modules/services/misc/dwm-status.nix10
-rw-r--r--nixos/modules/services/misc/freeswitch.nix9
-rw-r--r--nixos/modules/services/misc/gitea.nix7
-rw-r--r--nixos/modules/services/misc/gitlab.nix36
-rw-r--r--nixos/modules/services/misc/gollum.nix9
-rw-r--r--nixos/modules/services/misc/greenclip.nix7
-rw-r--r--nixos/modules/services/misc/heisenbridge.nix9
-rw-r--r--nixos/modules/services/misc/jackett.nix7
-rw-r--r--nixos/modules/services/misc/jellyfin.nix9
-rw-r--r--nixos/modules/services/misc/klipper.nix7
-rw-r--r--nixos/modules/services/misc/libreddit.nix7
-rw-r--r--nixos/modules/services/misc/lidarr.nix7
-rw-r--r--nixos/modules/services/misc/mbpfan.nix7
-rw-r--r--nixos/modules/services/misc/mediatomb.nix9
-rw-r--r--nixos/modules/services/misc/moonraker.nix9
-rw-r--r--nixos/modules/services/misc/nitter.nix7
-rw-r--r--nixos/modules/services/misc/ntfy-sh.nix7
-rw-r--r--nixos/modules/services/misc/nzbhydra2.nix7
-rw-r--r--nixos/modules/services/misc/paperless.nix7
-rw-r--r--nixos/modules/services/misc/plex.nix11
-rw-r--r--nixos/modules/services/misc/portunus.nix7
-rw-r--r--nixos/modules/services/misc/radarr.nix8
-rw-r--r--nixos/modules/services/misc/readarr.nix7
-rw-r--r--nixos/modules/services/misc/redmine.nix11
-rw-r--r--nixos/modules/services/misc/rippled.nix7
-rw-r--r--nixos/modules/services/misc/rmfakecloud.nix11
-rw-r--r--nixos/modules/services/misc/sickbeard.nix9
-rw-r--r--nixos/modules/services/misc/sonarr.nix9
-rw-r--r--nixos/modules/services/misc/sourcehut/default.nix21
-rw-r--r--nixos/modules/services/misc/spice-webdavd.nix7
-rw-r--r--nixos/modules/services/misc/tandoor-recipes.nix7
-rw-r--r--nixos/modules/services/misc/tautulli.nix9
-rw-r--r--nixos/modules/services/misc/tp-auto-kbbl.nix7
-rw-r--r--nixos/modules/services/misc/xmrig.nix8
-rw-r--r--nixos/modules/services/misc/zookeeper.nix7
-rw-r--r--nixos/modules/services/monitoring/arbtt.nix9
-rw-r--r--nixos/modules/services/monitoring/bosun.nix9
-rw-r--r--nixos/modules/services/monitoring/collectd.nix9
-rw-r--r--nixos/modules/services/monitoring/datadog-agent.nix15
-rw-r--r--nixos/modules/services/monitoring/grafana.nix7
-rw-r--r--nixos/modules/services/monitoring/heapster.nix7
-rw-r--r--nixos/modules/services/monitoring/karma.nix9
-rw-r--r--nixos/modules/services/monitoring/kthxbye.nix9
-rw-r--r--nixos/modules/services/monitoring/metricbeat.nix11
-rw-r--r--nixos/modules/services/monitoring/mimir.nix9
-rw-r--r--nixos/modules/services/monitoring/netdata.nix7
-rw-r--r--nixos/modules/services/monitoring/opentelemetry-collector.nix9
-rw-r--r--nixos/modules/services/monitoring/prometheus/alertmanager-irc-relay.nix7
-rw-r--r--nixos/modules/services/monitoring/prometheus/alertmanager.nix9
-rw-r--r--nixos/modules/services/monitoring/prometheus/default.nix9
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/pve.nix10
-rw-r--r--nixos/modules/services/monitoring/prometheus/pushgateway.nix9
-rw-r--r--nixos/modules/services/monitoring/scollector.nix9
-rw-r--r--nixos/modules/services/monitoring/telegraf.nix7
-rw-r--r--nixos/modules/services/monitoring/uptime-kuma.nix7
-rw-r--r--nixos/modules/services/monitoring/vmagent.nix9
-rw-r--r--nixos/modules/services/monitoring/vmalert.nix9
-rw-r--r--nixos/modules/services/monitoring/zabbix-agent.nix9
-rw-r--r--nixos/modules/services/network-filesystems/kubo.nix7
-rw-r--r--nixos/modules/services/network-filesystems/litestream/default.nix7
-rw-r--r--nixos/modules/services/network-filesystems/openafs/server.nix9
-rw-r--r--nixos/modules/services/network-filesystems/samba.nix10
-rw-r--r--nixos/modules/services/network-filesystems/tahoe.nix18
-rw-r--r--nixos/modules/services/networking/asterisk.nix7
-rw-r--r--nixos/modules/services/networking/avahi-daemon.nix9
-rw-r--r--nixos/modules/services/networking/bee.nix8
-rw-r--r--nixos/modules/services/networking/bind.nix7
-rw-r--r--nixos/modules/services/networking/bird-lg.nix7
-rw-r--r--nixos/modules/services/networking/birdwatcher.nix7
-rw-r--r--nixos/modules/services/networking/bitcoind.nix7
-rw-r--r--nixos/modules/services/networking/blockbook-frontend.nix7
-rw-r--r--nixos/modules/services/networking/cloudflared.nix7
-rw-r--r--nixos/modules/services/networking/consul.nix17
-rw-r--r--nixos/modules/services/networking/coredns.nix7
-rw-r--r--nixos/modules/services/networking/corerad.nix7
-rw-r--r--nixos/modules/services/networking/ejabberd.nix7
-rw-r--r--nixos/modules/services/networking/epmd.nix10
-rw-r--r--nixos/modules/services/networking/ferm.nix7
-rw-r--r--nixos/modules/services/networking/flannel.nix7
-rw-r--r--nixos/modules/services/networking/ghostunnel.nix8
-rw-r--r--nixos/modules/services/networking/gnunet.nix8
-rw-r--r--nixos/modules/services/networking/headscale.nix9
-rw-r--r--nixos/modules/services/networking/i2pd.nix9
-rw-r--r--nixos/modules/services/networking/icecream/daemon.nix7
-rw-r--r--nixos/modules/services/networking/icecream/scheduler.nix7
-rw-r--r--nixos/modules/services/networking/iscsi/initiator.nix7
-rw-r--r--nixos/modules/services/networking/iwd.nix11
-rw-r--r--nixos/modules/services/networking/knot.nix9
-rw-r--r--nixos/modules/services/networking/kresd.nix10
-rw-r--r--nixos/modules/services/networking/lambdabot.nix7
-rw-r--r--nixos/modules/services/networking/lokinet.nix7
-rw-r--r--nixos/modules/services/networking/miredo.nix9
-rw-r--r--nixos/modules/services/networking/morty.nix7
-rw-r--r--nixos/modules/services/networking/mosquitto.nix9
-rw-r--r--nixos/modules/services/networking/mtr-exporter.nix16
-rw-r--r--nixos/modules/services/networking/mullvad-vpn.nix10
-rw-r--r--nixos/modules/services/networking/multipath.nix7
-rw-r--r--nixos/modules/services/networking/murmur.nix7
-rw-r--r--nixos/modules/services/networking/mxisd.nix7
-rw-r--r--nixos/modules/services/networking/nebula.nix7
-rw-r--r--nixos/modules/services/networking/netbird.nix7
-rw-r--r--nixos/modules/services/networking/ngircd.nix9
-rw-r--r--nixos/modules/services/networking/nix-serve.nix9
-rw-r--r--nixos/modules/services/networking/nomad.nix9
-rw-r--r--nixos/modules/services/networking/ntp/chrony.nix9
-rw-r--r--nixos/modules/services/networking/pleroma.nix7
-rw-r--r--nixos/modules/services/networking/pppd.nix7
-rw-r--r--nixos/modules/services/networking/prosody.nix8
-rw-r--r--nixos/modules/services/networking/quassel.nix9
-rw-r--r--nixos/modules/services/networking/radvd.nix9
-rw-r--r--nixos/modules/services/networking/routedns.nix7
-rw-r--r--nixos/modules/services/networking/sabnzbd.nix7
-rw-r--r--nixos/modules/services/networking/seafile.nix7
-rw-r--r--nixos/modules/services/networking/searx.nix7
-rw-r--r--nixos/modules/services/networking/skydns.nix7
-rw-r--r--nixos/modules/services/networking/smokeping.nix7
-rw-r--r--nixos/modules/services/networking/softether.nix9
-rw-r--r--nixos/modules/services/networking/spacecookie.nix11
-rw-r--r--nixos/modules/services/networking/squid.nix7
-rw-r--r--nixos/modules/services/networking/strongswan-swanctl/module.nix9
-rw-r--r--nixos/modules/services/networking/syncthing.nix9
-rw-r--r--nixos/modules/services/networking/tayga.nix7
-rw-r--r--nixos/modules/services/networking/teleport.nix8
-rw-r--r--nixos/modules/services/networking/tinc.nix9
-rw-r--r--nixos/modules/services/networking/tmate-ssh-server.nix7
-rw-r--r--nixos/modules/services/networking/trickster.nix9
-rw-r--r--nixos/modules/services/networking/trust-dns.nix12
-rw-r--r--nixos/modules/services/networking/ucarp.nix9
-rw-r--r--nixos/modules/services/networking/unbound.nix7
-rw-r--r--nixos/modules/services/networking/unifi.nix23
-rw-r--r--nixos/modules/services/networking/v2ray.nix9
-rw-r--r--nixos/modules/services/networking/xandikos.nix7
-rw-r--r--nixos/modules/services/networking/xray.nix9
-rw-r--r--nixos/modules/services/networking/xrdp.nix9
-rw-r--r--nixos/modules/services/networking/yggdrasil.nix7
-rw-r--r--nixos/modules/services/networking/zeronet.nix10
-rw-r--r--nixos/modules/services/networking/zerotierone.nix9
-rw-r--r--nixos/modules/services/search/elasticsearch.nix7
-rw-r--r--nixos/modules/services/search/hound.nix9
-rw-r--r--nixos/modules/services/search/meilisearch.nix9
-rw-r--r--nixos/modules/services/security/authelia.nix7
-rw-r--r--nixos/modules/services/security/certmgr.nix7
-rw-r--r--nixos/modules/services/security/fail2ban.nix12
-rw-r--r--nixos/modules/services/security/haka.nix9
-rw-r--r--nixos/modules/services/security/nginx-sso.nix9
-rw-r--r--nixos/modules/services/security/oauth2_proxy.nix9
-rw-r--r--nixos/modules/services/security/pass-secret-service.nix8
-rw-r--r--nixos/modules/services/security/sks.nix7
-rw-r--r--nixos/modules/services/security/tor.nix7
-rw-r--r--nixos/modules/services/security/usbguard.nix10
-rw-r--r--nixos/modules/services/security/vault.nix7
-rw-r--r--nixos/modules/services/security/vaultwarden/default.nix7
-rw-r--r--nixos/modules/services/security/yubikey-agent.nix9
-rw-r--r--nixos/modules/services/system/automatic-timezoned.nix9
-rw-r--r--nixos/modules/services/system/cachix-agent/default.nix7
-rw-r--r--nixos/modules/services/system/cachix-watch-store.nix8
-rw-r--r--nixos/modules/services/system/saslauthd.nix7
-rw-r--r--nixos/modules/services/torrent/deluge.nix8
-rw-r--r--nixos/modules/services/torrent/opentracker.nix9
-rw-r--r--nixos/modules/services/torrent/rtorrent.nix9
-rw-r--r--nixos/modules/services/video/epgstation/default.nix8
-rw-r--r--nixos/modules/services/video/frigate.nix9
-rw-r--r--nixos/modules/services/video/unifi-video.nix27
-rw-r--r--nixos/modules/services/web-apps/akkoma.nix7
-rw-r--r--nixos/modules/services/web-apps/atlassian/confluence.nix20
-rw-r--r--nixos/modules/services/web-apps/atlassian/crowd.nix20
-rw-r--r--nixos/modules/services/web-apps/atlassian/jira.nix20
-rw-r--r--nixos/modules/services/web-apps/coder.nix9
-rw-r--r--nixos/modules/services/web-apps/documize.nix9
-rw-r--r--nixos/modules/services/web-apps/dokuwiki.nix18
-rw-r--r--nixos/modules/services/web-apps/engelsystem.nix9
-rw-r--r--nixos/modules/services/web-apps/ethercalc.nix7
-rw-r--r--nixos/modules/services/web-apps/fluidd.nix7
-rw-r--r--nixos/modules/services/web-apps/freshrss.nix7
-rw-r--r--nixos/modules/services/web-apps/galene.nix9
-rw-r--r--nixos/modules/services/web-apps/gerrit.nix14
-rw-r--r--nixos/modules/services/web-apps/healthchecks.nix7
-rw-r--r--nixos/modules/services/web-apps/invidious.nix7
-rw-r--r--nixos/modules/services/web-apps/jirafeau.nix7
-rw-r--r--nixos/modules/services/web-apps/jitsi-meet.nix2
-rw-r--r--nixos/modules/services/web-apps/keycloak.nix10
-rw-r--r--nixos/modules/services/web-apps/lanraragi.nix13
-rw-r--r--nixos/modules/services/web-apps/mainsail.nix7
-rw-r--r--nixos/modules/services/web-apps/matomo.nix11
-rw-r--r--nixos/modules/services/web-apps/mattermost.nix14
-rw-r--r--nixos/modules/services/web-apps/mediawiki.nix9
-rw-r--r--nixos/modules/services/web-apps/meme-bingo-web.nix9
-rw-r--r--nixos/modules/services/web-apps/miniflux.nix7
-rw-r--r--nixos/modules/services/web-apps/moodle.nix9
-rw-r--r--nixos/modules/services/web-apps/nextcloud.nix9
-rw-r--r--nixos/modules/services/web-apps/node-red.nix7
-rw-r--r--nixos/modules/services/web-apps/onlyoffice.nix7
-rw-r--r--nixos/modules/services/web-apps/openwebrx.nix7
-rw-r--r--nixos/modules/services/web-apps/pgpkeyserver-lite.nix9
-rw-r--r--nixos/modules/services/web-apps/phylactery.nix7
-rw-r--r--nixos/modules/services/web-apps/pict-rs.nix8
-rw-r--r--nixos/modules/services/web-apps/plantuml-server.nix12
-rw-r--r--nixos/modules/services/web-apps/sftpgo.nix9
-rw-r--r--nixos/modules/services/web-apps/shiori.nix7
-rw-r--r--nixos/modules/services/web-apps/vikunja.nix14
-rw-r--r--nixos/modules/services/web-apps/whitebophir.nix7
-rw-r--r--nixos/modules/services/web-apps/wordpress.nix7
-rw-r--r--nixos/modules/services/web-apps/youtrack.nix9
-rw-r--r--nixos/modules/services/web-apps/zabbix.nix9
-rw-r--r--nixos/modules/services/web-servers/agate.nix7
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix18
-rw-r--r--nixos/modules/services/web-servers/caddy/default.nix9
-rw-r--r--nixos/modules/services/web-servers/lighttpd/default.nix9
-rw-r--r--nixos/modules/services/web-servers/minio.nix7
-rw-r--r--nixos/modules/services/web-servers/phpfpm/default.nix9
-rw-r--r--nixos/modules/services/web-servers/tomcat.nix6
-rw-r--r--nixos/modules/services/web-servers/traefik.nix7
-rw-r--r--nixos/modules/services/web-servers/unit/default.nix7
-rw-r--r--nixos/modules/services/web-servers/varnish/default.nix9
-rw-r--r--nixos/modules/services/x11/desktop-managers/deepin.nix36
-rw-r--r--nixos/modules/services/x11/desktop-managers/kodi.nix10
-rw-r--r--nixos/modules/services/x11/desktop-managers/phosh.nix10
-rw-r--r--nixos/modules/services/x11/desktop-managers/retroarch.nix8
-rw-r--r--nixos/modules/services/x11/redshift.nix9
-rw-r--r--nixos/modules/services/x11/touchegg.nix7
-rw-r--r--nixos/modules/services/x11/unclutter-xfixes.nix7
-rw-r--r--nixos/modules/services/x11/unclutter.nix7
-rw-r--r--nixos/modules/services/x11/urxvtd.nix9
-rw-r--r--nixos/modules/services/x11/window-managers/awesome.nix7
-rw-r--r--nixos/modules/services/x11/window-managers/bspwm.nix20
-rw-r--r--nixos/modules/services/x11/window-managers/clfswm.nix9
-rw-r--r--nixos/modules/services/x11/window-managers/dwm.nix10
-rw-r--r--nixos/modules/services/x11/window-managers/herbstluftwm.nix9
-rw-r--r--nixos/modules/services/x11/window-managers/i3.nix9
-rw-r--r--nixos/modules/services/x11/window-managers/ragnarwm.nix9
-rw-r--r--nixos/modules/system/boot/unl0kr.nix89
-rw-r--r--nixos/modules/virtualisation/docker-rootless.nix9
-rw-r--r--nixos/modules/virtualisation/docker.nix9
-rw-r--r--nixos/modules/virtualisation/ecs-agent.nix7
-rw-r--r--nixos/modules/virtualisation/libvirtd.nix26
-rw-r--r--nixos/modules/virtualisation/openvswitch.nix9
-rw-r--r--nixos/modules/virtualisation/qemu-guest-agent.nix7
-rw-r--r--nixos/modules/virtualisation/virtualbox-host.nix9
-rw-r--r--nixos/modules/virtualisation/vmware-host.nix7
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/deepin.nix6
-rw-r--r--nixos/tests/jitsi-meet.nix26
-rw-r--r--nixos/tests/lanraragi.nix8
-rw-r--r--nixos/tests/matrix/synapse.nix44
-rw-r--r--nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix12
-rw-r--r--nixos/tests/nixops/default.nix6
-rw-r--r--nixos/tests/systemd-initrd-luks-unl0kr.nix75
396 files changed, 3096 insertions, 3383 deletions
diff --git a/nixos/doc/manual/installation/upgrading.chapter.md b/nixos/doc/manual/installation/upgrading.chapter.md
index d39e1b786d83..79cd4e55be5c 100644
--- a/nixos/doc/manual/installation/upgrading.chapter.md
+++ b/nixos/doc/manual/installation/upgrading.chapter.md
@@ -6,7 +6,7 @@ expressions and associated binaries. The NixOS channels are updated
 automatically from NixOS's Git repository after certain tests have
 passed and all packages have been built. These channels are:
 
--   *Stable channels*, such as [`nixos-23.05`](https://channels.nixos.org/nixos-23.05).
+-   *Stable channels*, such as [`nixos-23.11`](https://channels.nixos.org/nixos-23.11).
     These only get conservative bug fixes and package upgrades. For
     instance, a channel update may cause the Linux kernel on your system
     to be upgraded from 4.19.34 to 4.19.38 (a minor bug fix), but not
@@ -19,7 +19,7 @@ passed and all packages have been built. These channels are:
     radical changes between channel updates. It's not recommended for
     production systems.
 
--   *Small channels*, such as [`nixos-23.05-small`](https://channels.nixos.org/nixos-23.05-small)
+-   *Small channels*, such as [`nixos-23.11-small`](https://channels.nixos.org/nixos-23.11-small)
     or [`nixos-unstable-small`](https://channels.nixos.org/nixos-unstable-small).
     These are identical to the stable and unstable channels described above,
     except that they contain fewer binary packages. This means they get updated
@@ -38,8 +38,8 @@ newest supported stable release.
 
 When you first install NixOS, you're automatically subscribed to the
 NixOS channel that corresponds to your installation source. For
-instance, if you installed from a 23.05 ISO, you will be subscribed to
-the `nixos-23.05` channel. To see which NixOS channel you're subscribed
+instance, if you installed from a 23.11 ISO, you will be subscribed to
+the `nixos-23.11` channel. To see which NixOS channel you're subscribed
 to, run the following as root:
 
 ```ShellSession
@@ -54,16 +54,16 @@ To switch to a different NixOS channel, do
 ```
 
 (Be sure to include the `nixos` parameter at the end.) For instance, to
-use the NixOS 23.05 stable channel:
+use the NixOS 23.11 stable channel:
 
 ```ShellSession
-# nix-channel --add https://channels.nixos.org/nixos-23.05 nixos
+# nix-channel --add https://channels.nixos.org/nixos-23.11 nixos
 ```
 
 If you have a server, you may want to use the "small" channel instead:
 
 ```ShellSession
-# nix-channel --add https://channels.nixos.org/nixos-23.05-small nixos
+# nix-channel --add https://channels.nixos.org/nixos-23.11-small nixos
 ```
 
 And if you want to live on the bleeding edge:
@@ -114,5 +114,5 @@ the new generation contains a different kernel, initrd or kernel
 modules. You can also specify a channel explicitly, e.g.
 
 ```nix
-system.autoUpgrade.channel = "https://channels.nixos.org/nixos-23.05";
+system.autoUpgrade.channel = "https://channels.nixos.org/nixos-23.11";
 ```
diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md
index e8292087dc82..78e02c9d2446 100644
--- a/nixos/doc/manual/release-notes/rl-2311.section.md
+++ b/nixos/doc/manual/release-notes/rl-2311.section.md
@@ -1,260 +1,254 @@
-# Release 23.11 (“Tapir”, 2023.11/??) {#sec-release-23.11}
-
-## Highlights {#sec-release-23.11-highlights}
-
-- FoundationDB now defaults to major version 7.
-
-- PostgreSQL now defaults to major version 15.
-
-- GNOME has been updated to version 45, see the [release notes](https://release.gnome.org/45/) for details. Notably, Loupe has replaced Eye of GNOME as the default image viewer, Snapshot has replaced Cheese as the default camera application, and Photos will no longer be installed.
-
-- Support for WiFi6 (IEEE 802.11ax) and WPA3-SAE-PK was enabled in the `hostapd` package, along with a significant rework of the hostapd module.
-
-- LXD now supports virtual machine instances to complement the existing container support
-
-- The `nixos-rebuild` command has been given a `list-generations` subcommand. See `man nixos-rebuild` for more details.
-
-- [systemd](https://systemd.io) has been updated from v253 to v254, see [the release notes](https://github.com/systemd/systemd/blob/v254/NEWS#L3-L659) for more information on the changes.
-    - `boot.resumeDevice` **must be specified** when hibernating if not in EFI mode.
-    - systemd may warn your system about the permissions of your ESP partition (often `/boot`), this warning can be ignored for now, we are looking
-      into a satisfying solution regarding this problem.
-    - Updating with `nixos-rebuild boot` and rebooting is recommended, since in some rare cases the `nixos-rebuild switch` into the new generation on a live system might fail due to missing mount units.
-
-- [`sudo-rs`], a reimplementation of `sudo` in Rust, is now supported.
-  An experimental new module `security.sudo-rs` was added.
-  Switching to it (via ` security.sudo-rs.enable = true;`) introduces
-  slight changes in sudo behaviour, due to `sudo-rs`' current limitations:
-  - terminfo-related environment variables aren't preserved for `root` and `wheel`;
-  - `root` and `wheel` are not given the ability to set (or preserve)
-    arbitrary environment variables.
-
-  **Note:** The `sudo-rs` module only takes configuration through `security.sudo-rs`,
-  and in particular does not automatically use previously-set rules; this could be
-  achieved with `security.sudo-rs.extraRules = security.sudo.extraRules;` for instance.
-
-[`sudo-rs`]: https://github.com/memorysafety/sudo-rs/
-
-- [glibc](https://www.gnu.org/software/libc/) has been updated from version 2.37 to 2.38, see [the release notes](https://sourceware.org/glibc/wiki/Release/2.38) for what was changed.
-
-- `linuxPackages_testing_bcachefs` is now soft-deprecated by `linuxPackages_testing`.
-  - Please consider changing your NixOS configuration's `boot.kernelPackages` to `linuxPackages_testing` until a stable kernel with bcachefs support is released.
-
-- All [ROCm](https://rocm.docs.amd.com/en/latest/) packages have been updated to 5.7.0.
-  - [ROCm](https://rocm.docs.amd.com/en/latest/) package attribute sets are versioned: `rocmPackages` -> `rocmPackages_5`.
-
-- `yarn-berry` has been updated to 4.0.1. This means that NodeJS versions less than `18.12` are no longer supported by it. More details at the [upstream changelog](https://github.com/yarnpkg/berry/blob/master/CHANGELOG.md).
-
-- If the user has a custom shell enabled via `users.users.${USERNAME}.shell = ${CUSTOMSHELL}`, the
-  assertion will require them to also set `programs.${CUSTOMSHELL}.enable =
-  true`. This is generally safe behavior, but for anyone needing to opt out from
-  the check `users.users.${USERNAME}.ignoreShellProgramCheck = true` will do the job.
-
-- Cassandra now defaults to 4.x, updated from 3.11.x.
-
-## New Services {#sec-release-23.11-new-services}
-
-- [MCHPRS](https://github.com/MCHPR/MCHPRS), a multithreaded Minecraft server built for redstone. Available as [services.mchprs](#opt-services.mchprs.enable).
-
-- [acme-dns](https://github.com/joohoi/acme-dns), a limited DNS server to handle ACME DNS challenges easily and securely. Available as [services.acme-dns](#opt-services.acme-dns.enable).
-
-- [frp](https://github.com/fatedier/frp), a fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. Available as [services.frp](#opt-services.frp.enable).
-
-<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
-
-- [river](https://github.com/riverwm/river), A dynamic tiling wayland compositor. Available as [programs.river](#opt-programs.river.enable).
-
-- [wayfire](https://wayfire.org), A modular and extensible wayland compositor. Available as [programs.wayfire](#opt-programs.wayfire.enable).
-
-- [mautrix-whatsapp](https://docs.mau.fi/bridges/go/whatsapp/index.html) A Matrix-WhatsApp puppeting bridge
-
-- [hddfancontrol](https://github.com/desbma/hddfancontrol), a service to regulate fan speeds based on hard drive temperature. Available as [services.hddfancontrol](#opt-services.hddfancontrol.enable).
-
-- [seatd](https://sr.ht/~kennylevinsen/seatd/), A minimal seat management daemon. Available as [services.seatd](#opt-services.seatd.enable).
-
-- [GoToSocial](https://gotosocial.org/), an ActivityPub social network server, written in Golang. Available as [services.gotosocial](#opt-services.gotosocial.enable).
-
-- [Castopod](https://castopod.org/), an open-source hosting platform made for podcasters who want to engage and interact with their audience. Available as [services.castopod](#opt-services.castopod.enable).
-
-- [Typesense](https://github.com/typesense/typesense), a fast, typo-tolerant search engine for building delightful search experiences. Available as [services.typesense](#opt-services.typesense.enable).
-
-* [NS-USBLoader](https://github.com/developersu/ns-usbloader/), an all-in-one tool for managing Nintendo Switch homebrew. Available as [programs.ns-usbloader](#opt-programs.ns-usbloader.enable).
-
-- [Mobilizon](https://joinmobilizon.org/), a Fediverse platform for publishing events.
-
-- [Anuko Time Tracker](https://github.com/anuko/timetracker), a simple, easy to use, open source time tracking system. Available as [services.anuko-time-tracker](#opt-services.anuko-time-tracker.enable).
-
-- [Prometheus MySQL exporter](https://github.com/prometheus/mysqld_exporter), a MySQL server exporter for Prometheus. Available as [services.prometheus.exporters.mysqld](#opt-services.prometheus.exporters.mysqld.enable).
-
-- [LibreNMS](https://www.librenms.org), a auto-discovering PHP/MySQL/SNMP based network monitoring. Available as [services.librenms](#opt-services.librenms.enable).
-
-- [Livebook](https://livebook.dev/), an interactive notebook with support for Elixir, graphs, machine learning, and more.
-
-- [sitespeed-io](https://sitespeed.io), a tool that can generate metrics (timings, diagnostics) for websites. Available as [services.sitespeed-io](#opt-services.sitespeed-io.enable).
-
-- [stalwart-mail](https://stalw.art), an all-in-one email server (SMTP, IMAP, JMAP). Available as [services.stalwart-mail](#opt-services.stalwart-mail.enable).
-
-- [tang](https://github.com/latchset/tang), a server for binding data to network presence. Available as [services.tang](#opt-services.tang.enable).
-
-- [Jool](https://nicmx.github.io/Jool/en/index.html), a kernelspace NAT64 and SIIT implementation, providing translation between IPv4 and IPv6. Available as [networking.jool.enable](#opt-networking.jool.enable).
-
-- [Home Assistant Satellite], a streaming audio satellite for Home Assistant voice pipelines, where you can reuse existing mic/speaker hardware. Available as [services.homeassistant-satellite](#opt-services.homeassistant-satellite.enable).
-
-- [Apache Guacamole](https://guacamole.apache.org/), a cross-platform, clientless remote desktop gateway. Available as [services.guacamole-server](#opt-services.guacamole-server.enable) and [services.guacamole-client](#opt-services.guacamole-client.enable) services.
-
-- [pgBouncer](https://www.pgbouncer.org), a PostgreSQL connection pooler. Available as [services.pgbouncer](#opt-services.pgbouncer.enable).
-
-- [Goss](https://goss.rocks/), a YAML based serverspec alternative tool for validating a server's configuration. Available as [services.goss](#opt-services.goss.enable).
-
-- [trust-dns](https://trust-dns.org/), a Rust based DNS server built to be safe and secure from the ground up. Available as [services.trust-dns](#opt-services.trust-dns.enable).
-
-- [osquery](https://www.osquery.io/), a SQL powered operating system instrumentation, monitoring, and analytics.
-
-- [ebusd](https://ebusd.eu), a daemon for handling communication with eBUS devices connected to a 2-wire bus system (“energy bus” used by numerous heating systems). Available as [services.ebusd](#opt-services.ebusd.enable).
-
-- [systemd-sysupdate](https://www.freedesktop.org/software/systemd/man/systemd-sysupdate.html), atomically updates the host OS, container images, portable service images or other sources. Available as [systemd.sysupdate](opt-systemd.sysupdate).
-
-- [eris-server](https://codeberg.org/eris/eris-go). [ERIS](https://eris.codeberg.page/) is an encoding for immutable storage and this server provides block exchange as well as content decoding over HTTP and through a FUSE file-system. Available as [services.eris-server](#opt-services.eris-server.enable).
-
-- [forgejo](https://forgejo.org/), a git forge. Previously deployed as a drop-in replacement package in the [gitea module](#opt-services.gitea.package). Available as [services.forgejo](#opt-services.forgejo.enable). See migration instructions in the [NixOS manual](#module-forgejo) on how to migrate your forgejo instance using [`services.gitea.package = pkgs.forgejo`](#opt-services.gitea.package) to [`services.forgejo`](#opt-services.forgejo.enable).
-
-- hardware/infiniband.nix adds infiniband subnet manager support using an [opensm](https://github.com/linux-rdma/opensm) systemd-template service, instantiated on card guids. The module also adds kernel modules and cli tooling to help administrators debug and measure performance. Available as [hardware.infiniband.enable](#opt-hardware.infiniband.enable).
-
-- [zwave-js](https://github.com/zwave-js/zwave-js-server), a small server wrapper around Z-Wave JS to access it via a WebSocket. Available as [services.zwave-js](#opt-services.zwave-js.enable).
-
-- [Honk](https://humungus.tedunangst.com/r/honk), a complete ActivityPub server with minimal setup and support costs.
-  Available as [services.honk](#opt-services.honk.enable).
-
-- [ferretdb](https://www.ferretdb.io/), an open-source proxy, converting the MongoDB 6.0+ wire protocol queries to PostgreSQL or SQLite. Available as [services.ferretdb](options.html#opt-services.ferretdb.enable).
-
-- [MicroBin](https://microbin.eu/), a feature rich, performant and secure text and file sharing web application, a "paste bin". Available as [services.microbin](#opt-services.microbin.enable).
-
-- [NNCP](http://www.nncpgo.org/). Added nncp-daemon and nncp-caller services. Configuration is set with [programs.nncp.settings](#opt-programs.nncp.settings) and the daemons are enabled at [services.nncp](#opt-services.nncp.caller.enable).
-
-- [FastNetMon Advanced](https://fastnetmon.com/product-overview/), a commercial high performance DDoS detector / sensor. Available as [services.fastnetmon-advanced](#opt-services.fastnetmon-advanced.enable).
-
-- [tuxedo-rs](https://github.com/AaronErhardt/tuxedo-rs), Rust utilities for interacting with hardware from TUXEDO Computers.
-
-- [certspotter](https://github.com/SSLMate/certspotter), a certificate transparency log monitor. Available as [services.certspotter](#opt-services.certspotter.enable).
-
-- [audiobookshelf](https://github.com/advplyr/audiobookshelf/), a self-hosted audiobook and podcast server. Available as [services.audiobookshelf](#opt-services.audiobookshelf.enable).
-
-- [ZITADEL](https://zitadel.com), a turnkey identity and access management platform. Available as [services.zitadel](#opt-services.zitadel.enable).
-
-- [exportarr](https://github.com/onedr0p/exportarr), Prometheus Exporters for Bazarr, Lidarr, Prowlarr, Radarr, Readarr, and Sonarr. Available as [services.prometheus.exporters.exportarr-bazarr](#opt-services.prometheus.exporters.exportarr-bazarr.enable)/[services.prometheus.exporters.exportarr-lidarr](#opt-services.prometheus.exporters.exportarr-lidarr.enable)/[services.prometheus.exporters.exportarr-prowlarr](#opt-services.prometheus.exporters.exportarr-prowlarr.enable)/[services.prometheus.exporters.exportarr-radarr](#opt-services.prometheus.exporters.exportarr-radarr.enable)/[services.prometheus.exporters.exportarr-readarr](#opt-services.prometheus.exporters.exportarr-readarr.enable)/[services.prometheus.exporters.exportarr-sonarr](#opt-services.prometheus.exporters.exportarr-sonarr.enable).
-
-- [netclient](https://github.com/gravitl/netclient), an automated WireGuard® Management Client. Available as [services.netclient](#opt-services.netclient.enable).
-
-- [trunk-ng](https://github.com/ctron/trunk), A fork of `trunk`: Build, bundle & ship your Rust WASM application to the web
-
-- [virt-manager](https://virt-manager.org/), an UI for managing virtual machines in libvirt, is now available as `programs.virt-manager`.
-
-- [Soft Serve](https://github.com/charmbracelet/soft-serve), a tasty, self-hostable Git server for the command line. Available as [services.soft-serve](#opt-services.soft-serve.enable).
-
-- [Rosenpass](https://rosenpass.eu/), a service for post-quantum-secure VPNs with WireGuard. Available as [services.rosenpass](#opt-services.rosenpass.enable).
-
-- [c2FmZQ](https://github.com/c2FmZQ/c2FmZQ/), an application that can securely encrypt, store, and share files, including but not limited to pictures and videos. Available as [services.c2fmzq-server](#opt-services.c2fmzq-server.enable).
-
-- [preload](http://sourceforge.net/projects/preload), a service that makes applications run faster by prefetching binaries and shared objects.  Available as [services.preload](#opt-services.preload.enable).
-
-## Backward Incompatibilities {#sec-release-23.11-incompatibilities}
-
-- `services.postgresql.ensurePermissions` has been deprecated in favor of `services.postgresql.ensureUsers.*.ensureDBOwnership` which simplifies the setup of database owned by a certain system user
-  in local database contexts (which make use of peer authentication via UNIX sockets), migration guidelines were provided in the NixOS manual, please refer to them if you are affected by a PostgreSQL 15 changing the way `GRANT ALL PRIVILEGES` is working. `services.postgresql.ensurePermissions` will be removed in 24.05. All NixOS modules were migrated using one of the strategy, e.g. `ensureDBOwnership` or `postStart`. More about this situation can be learnt in https://github.com/NixOS/nixpkgs/pull/266270.
-
-- `network-online.target` has been fixed to no longer time out for systems with `networking.useDHCP = true` and `networking.useNetworkd = true`.
-  Workarounds for this can be removed.
-
-- The `boot.loader.raspberryPi` options have been marked deprecated, with intent for removal for NixOS 24.11. They had a limited use-case, and do not work like people expect. They required either very old installs ([before mid-2019](https://github.com/NixOS/nixpkgs/pull/62462)) or customized builds out of scope of the standard and generic AArch64 support. That option set never supported the Raspberry Pi 4 family of devices.
-
-- `python3.pkgs.sequoia` was removed in favor of `python3.pkgs.pysequoia`. The latter package is based on upstream's dedicated repository for sequoia's Python bindings, where the Python bindings from [gitlab:sequoia-pgp/sequoia](https://gitlab.com/sequoia-pgp/sequoia) were removed long ago.
-
-- `writeTextFile` now requires `executable` to be boolean, values like `null` or `""` will now fail to evaluate.
-
-- The latest version of `clonehero` now stores custom content in `~/.clonehero`. See the [migration instructions](https://clonehero.net/2022/11/29/v23-to-v1-migration-instructions.html). Typically, these content files would exist along side the binary, but the previous build used a wrapper script that would store them in `~/.config/unity3d/srylain Inc_/Clone Hero`.
-
-- `services.mastodon` doesn't support providing a TCP port to its `streaming` component anymore, as upstream implemented parallelization by running multiple instances instead of running multiple processes in one instance. Please create a PR if you are interested in this feature.
-
-- The `services.hostapd` module was rewritten to support `passwordFile` like options, WPA3-SAE, and management of multiple interfaces. This breaks compatibility with older configurations.
-  - `hostapd` is now started with additional systemd sandbox/hardening options for better security.
-  - `services.hostapd.interface` was replaced with a per-radio and per-bss configuration scheme using [services.hostapd.radios](#opt-services.hostapd.radios).
-  - `services.hostapd.wpa` has been replaced by [services.hostapd.radios.&lt;name&gt;.networks.&lt;name&gt;.authentication.wpaPassword](#opt-services.hostapd.radios._name_.networks._name_.authentication.wpaPassword) and [services.hostapd.radios.&lt;name&gt;.networks.&lt;name&gt;.authentication.saePasswords](#opt-services.hostapd.radios._name_.networks._name_.authentication.saePasswords) which configure WPA2-PSK and WP3-SAE respectively.
-  - The default authentication has been changed to WPA3-SAE. Options for other (legacy) schemes are still available.
-
-- `python3.pkgs.fetchPypi` (and `python3Packages.fetchPypi`) has been deprecated in favor of top-level `fetchPypi`.
-
-- xdg-desktop-portal has been updated to 1.18, which reworked how portal implementations are selected. If you roll your own desktop environment, you should either set `xdg.portal.config` or `xdg.portal.configPackages`, which allow fine-grained control over which portal backend to use for specific interfaces, as described in {manpage}`portals.conf(5)`.
-
-  If you don't provide configurations, a portal backend will only be considered when the desktop you use matches its deprecated `UseIn` key. While some NixOS desktop modules should already ship one for you, it is suggested to test portal availability by trying [Door Knocker](https://flathub.org/apps/xyz.tytanium.DoorKnocker) and [ASHPD Demo](https://flathub.org/apps/com.belmoussaoui.ashpd.demo). If things regressed, you may run `G_MESSAGES_DEBUG=all /path/to/xdg-desktop-portal/libexec/xdg-desktop-portal` for ideas on which config file and which portals are chosen.
-
-- `pass` now does not contain `password-store.el`.  Users should get `password-store.el` from Emacs lisp package set `emacs.pkgs.password-store`.
-
-- `services.knot` now supports `.settings` from RFC42.  The previous `.extraConfig` still works the same, but it displays a warning now.
-
-- `services.invoiceplane` now supports .settings from RFC42. The previous .extraConfig still works the same, but it displays a warning now.
-
-- `mu` now does not install `mu4e` files by default.  Users should get `mu4e` from Emacs lisp package set `emacs.pkgs.mu4e`.
-
-- `mariadb` now defaults to `mariadb_1011` instead of `mariadb_106`, meaning the default version was upgraded from 10.6.x to 10.11.x. See the [upgrade notes](https://mariadb.com/kb/en/upgrading-from-mariadb-10-6-to-mariadb-10-11/) for potential issues.
-
-- `getent` has been moved from `glibc`'s `bin` output to its own dedicated output, reducing closure size for many dependents. Dependents using the `getent` alias should not be affected; others should move from using `glibc.bin` or `getBin glibc` to `getent` (which also improves compatibility with non-glibc platforms).
+# Release 23.11 (“Tapir”, 2023.11/29) {#sec-release-23.11}
+
+The NixOS release team is happy to announce a new version of NixOS. The release is called NixOS 23.11 ("Tapir").
+
+NixOS is a Linux distribution, whose set of packages can also be used on other Linux systems and macOS.
+
+Support is planned until the end of June 2024, handing over to NixOS 24.05.
+
+To upgrade to the latest release, follow the upgrade chapter and check the [Breaking Changes](#sec-release-23.11-nixos-breaking-changes)
+section for packages and services used in your configuration.
+
+The team is excited about the many software updates and improvements in this release. Just to name a few, do check the updates
+for `GNOME` packages, `systemd`, `glibc`, the `ROCM` package set, and `hostapd` (which brings support for WiFi6 (IEEE 802.11ax) and WPA3-SAE-PK).
+
+Make sure to also check the many updates in the [Nixpkgs library](#sec-release-23.11-nixpkgs-lib) when developing your own packages.
+
+## Table of Contents {#sec-release-23.11-toc}
+
+- [NixOS](#sec-release-23.11-nixos)
+  - [Breaking Changes](#sec-release-23.11-nixos-breaking-changes)
+  - [New Services](#sec-release-23.11-nixos-new-services)
+  - [Other Notable Changes](#sec-release-23.11-nixos-notable-changes)
+- [Nixpkgs Library Changes](#sec-release-23.11-nixpkgs-lib)
+  - [Breaking Changes](#sec-release-23.11-lib-breaking)
+  - [Additions and Improvements](#sec-release-23.11-lib-additions-improvements)
+  - [Deprecations](#sec-release-23.11-lib-deprecations)
+
+## NixOS {#sec-release-23.11-nixos}
+
+
+### Breaking Changes {#sec-release-23.11-nixos-breaking-changes}
+
+- `services.postgresql.ensurePermissions` has been deprecated in favor of
+  `services.postgresql.ensureUsers.*.ensureDBOwnership` which simplifies the
+  setup of database owned by a certain system user in local database contexts
+  (which make use of peer authentication via UNIX sockets), migration
+  guidelines were provided in the NixOS manual, please refer to them if you are
+  affected by a PostgreSQL 15 changing the way `GRANT ALL PRIVILEGES` is
+  working. `services.postgresql.ensurePermissions` will be removed in 24.05.
+  All NixOS modules were migrated using one of the strategy, e.g.
+  `ensureDBOwnership` or `postStart`. Refer to the [PR
+  #266270](https://github.com/NixOS/nixpkgs/pull/266270) for more details.
+
+- `network-online.target` has been fixed to no longer time out for systems with
+  `networking.useDHCP = true` and `networking.useNetworkd = true`. Workarounds
+  for this can be removed.
+
+- The `boot.loader.raspberryPi` options have been marked deprecated, with
+  intent of removal for NixOS 24.11. They had a limited use-case, and do not
+  work like people expect. They required either very old installs from ([before
+  mid-2019](https://github.com/NixOS/nixpkgs/pull/62462)) or customized builds
+  out of scope of the standard and generic AArch64 support. That option set
+  never supported the Raspberry Pi 4 family of devices.
+
+- `python3.pkgs.sequoia` was removed in favor of `python3.pkgs.pysequoia`. The
+  latter package is based on upstream's dedicated repository for sequoia's
+  Python bindings, where the Python bindings from
+  [gitlab:sequoia-pgp/sequoia](https://gitlab.com/sequoia-pgp/sequoia) were
+  removed long ago.
+
+- `writeTextFile` requires `executable` to be boolean now, values like `null`
+  or `""` will fail to evaluate now.
+
+- The latest version of `clonehero` now stores custom content in
+  `~/.clonehero`. Refer to the [migration
+  instructions](https://clonehero.net/2022/11/29/v23-to-v1-migration-instructions.html)
+  for more details. Typically, these content files would exist along side the
+  binary, but the previous build used a wrapper script that would store them in
+  `~/.config/unity3d/srylain Inc_/Clone Hero`.
+
+- `services.mastodon` doesn't support providing a TCP port to its `streaming`
+  component anymore, as upstream implemented parallelization by running
+  multiple instances instead of running multiple processes in one instance.
+  Please create a PR if you are interested in this feature.
+
+- The `services.hostapd` module was rewritten to support `passwordFile` like
+  options, WPA3-SAE, and management of multiple interfaces. This breaks
+  compatibility with older configurations.
+  - `hostapd` is now started with additional systemd sandbox/hardening options
+    for better security.
+  - `services.hostapd.interface` was replaced with a per-radio and per-bss
+    configuration scheme using
+    [services.hostapd.radios](#opt-services.hostapd.radios).
+  - `services.hostapd.wpa` has been replaced by
+    [services.hostapd.radios.&lt;name&gt;.networks.&lt;name&gt;.authentication.wpaPassword](#opt-services.hostapd.radios._name_.networks._name_.authentication.wpaPassword)
+    and
+    [services.hostapd.radios.&lt;name&gt;.networks.&lt;name&gt;.authentication.saePasswords](#opt-services.hostapd.radios._name_.networks._name_.authentication.saePasswords)
+    which configure WPA2-PSK and WP3-SAE respectively.
+  - The default authentication has been changed to WPA3-SAE. Options for other
+    (legacy) schemes are still available.
+
+- `python3.pkgs.fetchPypi` and `python3Packages.fetchPypi` have been
+  deprecated in favor of top-level `fetchPypi`.
+
+- xdg-desktop-portal has been updated to 1.18, which reworked how portal
+  implementations are selected. If you roll your own desktop environment, you
+  should either set `xdg.portal.config` or `xdg.portal.configPackages`, which
+  allow fine-grained control over which portal backend to use for specific
+  interfaces, as described in {manpage}`portals.conf(5)`.
+
+  If you don't provide configurations, a portal backend will only be considered
+  when the desktop you use matches its deprecated `UseIn` key. While some NixOS
+  desktop modules should already ship one for you, it is suggested to test
+  portal availability by trying [Door
+  Knocker](https://flathub.org/apps/xyz.tytanium.DoorKnocker) and [ASHPD
+  Demo](https://flathub.org/apps/com.belmoussaoui.ashpd.demo). If things
+  regressed, you may run `G_MESSAGES_DEBUG=all
+  /path/to/xdg-desktop-portal/libexec/xdg-desktop-portal` for ideas on which
+  config file and which portals are chosen.
+
+- `pass` now does not contain `password-store.el`. Users should get
+  `password-store.el` from Emacs lisp package set `emacs.pkgs.password-store`.
+
+- `services.knot` now supports `.settings` from RFC42.  The previous
+  `.extraConfig` still works the same, but it displays a warning now.
+
+- `services.invoiceplane` now supports `.settings` from RFC42. The previous
+  `.extraConfig` still works the same way, but it displays a warning now.
+
+- `mu` does not install `mu4e` files by default now. Users should get `mu4e`
+  from Emacs lisp package set `emacs.pkgs.mu4e`.
+
+- `mariadb` now defaults to `mariadb_1011` instead of `mariadb_106`, meaning
+  the default version was upgraded from v10.6.x to v10.11.x. Refer to the
+  [upgrade
+  notes](https://mariadb.com/kb/en/upgrading-from-mariadb-10-6-to-mariadb-10-11/)
+  for potential issues.
+
+- `getent` has been moved from `glibc`'s `bin` output to its own dedicated
+  output, reducing closure size for many dependents. Dependents using the
+  `getent` alias should not be affected; others should move from using
+  `glibc.bin` or `getBin glibc` to `getent` (which also improves compatibility
+  with non-glibc platforms).
 
 - `maintainers/scripts/update-luarocks-packages` is now a proper package
   `luarocks-packages-updater` that can be run to maintain out-of-tree luarocks
-  packages
+  packages.
 
-- The `users.users.<name>.passwordFile` has been renamed to `users.users.<name>.hashedPasswordFile` to avoid possible confusions. The option is in fact the file-based version of `hashedPassword`, not `password`, and expects a file containing the {manpage}`crypt(3)` hash of the user password.
+- The `users.users.<name>.passwordFile` has been renamed to
+  `users.users.<name>.hashedPasswordFile` to avoid possible confusions. The
+  option is in fact the file-based version of `hashedPassword`, not `password`,
+  and expects a file containing the {manpage}`crypt(3)` hash of the user
+  password.
 
-- `chromiumBeta` and `chromiumDev` have been removed due to the lack of maintenance in nixpkgs. Consider using `chromium` instead.
+- `chromiumBeta` and `chromiumDev` have been removed due to the lack of
+  maintenance in nixpkgs. Consider using `chromium` instead.
 
-- `google-chrome-beta` and `google-chrome-dev` have been removed due to the lack of maintenance in nixpkgs. Consider using `google-chrome` instead.
+- `google-chrome-beta` and `google-chrome-dev` have been removed due to the
+  lack of maintenance in nixpkgs. Consider using `google-chrome` instead.
 
-- The `services.ananicy.extraRules` option now has the type of `listOf attrs` instead of `string`.
+- The `services.ananicy.extraRules` option now has the type of `listOf attrs`
+  instead of `string`.
 
 - `buildVimPluginFrom2Nix` has been renamed to `buildVimPlugin`, which now
-  now skips `configurePhase` and `buildPhase`
-
-- JACK tools (`jack_*` except `jack_control`) have moved from the `jack2` package to `jack-example-tools`
-
-- The `waagent` service does provisioning now
-
-- The `matrix-synapse` package & module have undergone some significant internal changes, for most setups no intervention is needed, though:
-  - The option [`services.matrix-synapse.package`](#opt-services.matrix-synapse.package) is now read-only. For modifying the package, use an overlay which modifies `matrix-synapse-unwrapped` instead. More on that below.
-  - The `enableSystemd` & `enableRedis` arguments have been removed and `matrix-synapse` has been renamed to `matrix-synapse-unwrapped`. Also, several optional dependencies (such as `psycopg2` or `authlib`) have been removed.
-  - These optional dependencies are automatically added via a wrapper (`pkgs.matrix-synapse.override { extras = ["redis"]; }` for `hiredis` & `txredisapi` for instance) if the relevant config section is declared in `services.matrix-synapse.settings`. For instance, if `services.matrix-synapse.settings.redis.enabled` is set to `true`, `"redis"` will be automatically added to the `extras` list of `pkgs.matrix-synapse`.
-  - A list of all extras (and the extras enabled by default) can be found at the [option's reference for `services.matrix-synapse.extras`](#opt-services.matrix-synapse.extras).
-  - In some cases (e.g. for running synapse workers) it was necessary to re-use the `PYTHONPATH` of `matrix-synapse.service`'s environment to have all plugins available. This isn't necessary anymore, instead `config.services.matrix-synapse.package` can be used as it points to the wrapper with properly configured `extras` and also all plugins defined via [`services.matrix-synapse.plugins`](#opt-services.matrix-synapse.plugins) available. This is also the reason for why the option is read-only now, it's supposed to be set by the module only.
-
-- `netbox` was updated to 3.6. NixOS' `services.netbox.package` still defaults to 3.5 if `stateVersion` is earlier than 23.11. Please review upstream's breaking changes [for 3.6.0](https://github.com/netbox-community/netbox/releases/tag/v3.6.0) and upgrade NetBox by changing `services.netbox.package`. Database migrations will be run automatically.
-
-- `etcd` has been updated to 3.5, you will want to read the [3.3 to 3.4](https://etcd.io/docs/v3.5/upgrades/upgrade_3_4/) and [3.4 to 3.5](https://etcd.io/docs/v3.5/upgrades/upgrade_3_5/) upgrade guides
-
-- `gitlab` installations created or updated between versions \[15.11.0, 15.11.2] have an incorrect database schema. This will become a problem when upgrading to `gitlab` >=16.2.0. A workaround for affected users can be found in the [GitLab docs](https://docs.gitlab.com/ee/update/versions/gitlab_16_changes.html#undefined-column-error-upgrading-to-162-or-later).
-
-- `consul` has been updated to `1.16.0`. See the [release note](https://github.com/hashicorp/consul/releases/tag/v1.16.0) for more details. Once a new Consul version has started and upgraded its data directory, it generally cannot be downgraded to the previous version.
+  now skips `configurePhase` and `buildPhase`.
+
+- JACK tools (`jack_*` except `jack_control`) have moved from the `jack2`
+  package to `jack-example-tools`.
+
+- The `waagent` service does provisioning now.
+
+- The `matrix-synapse` package & module have undergone some significant
+  internal changes, for most setups no intervention is needed, though:
+  - The option
+    [`services.matrix-synapse.package`](#opt-services.matrix-synapse.package)
+    is read-only now. For modifying the package, use an overlay which modifies
+    `matrix-synapse-unwrapped` instead. More on that below.
+  - The `enableSystemd` & `enableRedis` arguments have been removed and
+    `matrix-synapse` has been renamed to `matrix-synapse-unwrapped`. Also,
+    several optional dependencies (such as `psycopg2` or `authlib`) have been
+    removed.
+  - These optional dependencies are automatically added via a wrapper
+    (`pkgs.matrix-synapse.override { extras = ["redis"]; }` for `hiredis` &
+    `txredisapi` for instance) if the relevant config section is declared in
+    `services.matrix-synapse.settings`. For instance, if
+    `services.matrix-synapse.settings.redis.enabled` is set to `true`,
+    `"redis"` will be automatically added to the `extras` list of
+    `pkgs.matrix-synapse`.
+  - A list of all extras (and the extras enabled by default) can be found at
+    the [option's reference for
+    `services.matrix-synapse.extras`](#opt-services.matrix-synapse.extras).
+  - In some cases (e.g. for running synapse workers) it was necessary to re-use
+    the `PYTHONPATH` of `matrix-synapse.service`'s environment to have all
+    plugins available. This isn't necessary anymore, instead
+    `config.services.matrix-synapse.package` can be used as it points to the
+    wrapper with properly configured `extras` and also all plugins defined via
+    [`services.matrix-synapse.plugins`](#opt-services.matrix-synapse.plugins)
+    available. This is also the reason for why the option is read-only now,
+    it's supposed to be set by the module only.
+
+- `netbox` was updated to v3.6. `services.netbox.package` still defaults
+  to v3.5 if `stateVersion` is earlier than 23.11. Refer to upstream's breaking
+  changes [for
+  v3.6.0](https://github.com/netbox-community/netbox/releases/tag/v3.6.0) and
+  upgrade NetBox by changing `services.netbox.package`. Database migrations
+  will be run automatically.
+
+- `etcd` has been updated to v3.5. Refer to upgrade guides for [v3.3 to
+  v3.4](https://etcd.io/docs/v3.5/upgrades/upgrade_3_4/) and [v3.4 to
+  v3.5](https://etcd.io/docs/v3.5/upgrades/upgrade_3_5/) for more details.
+
+- `gitlab` installations created or updated between versions \[15.11.0,
+  15.11.2] have an incorrect database schema. This will become a problem when
+  upgrading to `gitlab` >=16.2.0. A workaround for affected users can be found
+  in the [GitLab
+  docs](https://docs.gitlab.com/ee/update/versions/gitlab_16_changes.html#undefined-column-error-upgrading-to-162-or-later).
+
+
+- `consul` has been updated to v1.16.0. Refer to the [release
+  note](https://github.com/hashicorp/consul/releases/tag/v1.16.0) for more
+  details. Once a new Consul version has started and upgraded it's data
+  directory, it generally cannot be downgraded to the previous version.
 
 - `llvmPackages_rocm` has been moved to `rocmPackages.llvm`.
 
-- `hip`, `rocm-opencl-runtime`, `rocm-opencl-icd`, and `rocclr` have been combined into `rocmPackages.clr`.
+- `hip`, `rocm-opencl-runtime`, `rocm-opencl-icd`, and `rocclr` have been
+  combined into `rocmPackages.clr`.
 
 - `clang-ocl`, `clr`, `composable_kernel`, `hipblas`, `hipcc`, `hip-common`, `hipcub`,
   `hipfft`, `hipfort`, `hipify`, `hipsolver`, `hipsparse`, `migraphx`, `miopen`, `miopengemm`,
   `rccl`, `rdc`, `rocalution`, `rocblas`, `rocdgbapi`, `rocfft`, `rocgdb`, `rocm-cmake`,
   `rocm-comgr`, `rocm-core`, `rocm-device-libs`, `rocminfo`, `rocmlir`, `rocm-runtime`,
   `rocm-smi`, `rocm-thunk`, `rocprim`, `rocprofiler`, `rocrand`, `rocr-debug-agent`,
-  `rocsolver`, `rocsparse`, `rocthrust`, `roctracer`, `rocwmma`, and `tensile` have been moved to `rocmPackages`.
-
-- `himalaya` has been updated to `0.8.0`, which drops the native TLS support (in favor of Rustls) and add OAuth 2.0 support. See the [release note](https://github.com/soywod/himalaya/releases/tag/v0.8.0) for more details.
-
-- `nix-prefetch-git` now ignores global and user git config, to improve reproducibility.
-
-- The [services.caddy.acmeCA](#opt-services.caddy.acmeCA) option now defaults to `null` instead of `"https://acme-v02.api.letsencrypt.org/directory"`, to use all of Caddy's default ACME CAs and enable Caddy's automatic issuer fallback feature by default, as recommended by upstream.
-
-- The default priorities of [`services.nextcloud.phpOptions`](#opt-services.nextcloud.phpOptions) have changed. This means that e.g.
-  `services.nextcloud.phpOptions."opcache.interned_strings_buffer" = "23";` doesn't discard all of the other defaults from this option
-  anymore. The attribute values of `phpOptions` are still defaults, these can be overridden as shown here.
-
-  To override all of the options (including including `upload_max_filesize`, `post_max_size`
-  and `memory_limit` which all point to [`services.nextcloud.maxUploadSize`](#opt-services.nextcloud.maxUploadSize)
+  `rocsolver`, `rocsparse`, `rocthrust`, `roctracer`, `rocwmma`, and `tensile`
+  have been moved to `rocmPackages`.
+
+- `himalaya` has been updated to v0.8.0, which drops the native TLS support
+  (in favor of Rustls) and add OAuth 2.0 support. Refer to the [release
+  note](https://github.com/soywod/himalaya/releases/tag/v0.8.0) for more
+  details.
+
+
+- `nix-prefetch-git` now ignores global and user git config, to improve
+  reproducibility.
+
+- The [services.caddy.acmeCA](#opt-services.caddy.acmeCA) option defaults
+  to `null` instead of `"https://acme-v02.api.letsencrypt.org/directory"` now.
+  To use all of Caddy's default ACME CAs and enable Caddy's automatic issuer
+  fallback feature by default, as recommended by upstream.
+
+- The default priorities of
+  [`services.nextcloud.phpOptions`](#opt-services.nextcloud.phpOptions) have
+  changed. This means that e.g.
+  `services.nextcloud.phpOptions."opcache.interned_strings_buffer" = "23";`
+  doesn't discard all of the other defaults from this option anymore. The
+  attribute values of `phpOptions` are still defaults, these can be overridden
+  as shown here.
+
+  To override all of the options (including including `upload_max_filesize`,
+  `post_max_size` and `memory_limit` which all point to
+  [`services.nextcloud.maxUploadSize`](#opt-services.nextcloud.maxUploadSize)
   by default) can be done like this:
 
   ```nix
@@ -265,295 +259,977 @@
   }
   ```
 
-- `php80` is no longer supported due to upstream not supporting this version anymore.
+- `php80` is no longer supported due to upstream not supporting this version
+  anymore.
 
-- PHP now defaults to PHP 8.2, updated from 8.1.
+- PHP defaults to PHP 8.2 now, updated from v8.1.
 
-- GraalVM has been updated to the latest version, and this brings significant changes. Upstream don't release multiple versions targeting different JVMs anymore, so now we only have one GraalVM derivation (`graalvm-ce`). While at first glance the version may seem a downgrade (22.3.1 -> 21.0.0), the major version is now following the JVM it targets (so this latest version targets JVM 21). Also some products like `llvm-installable-svm` and `native-image-svm` were incorporate to the main GraalVM derivation, so they're included by default.
+- GraalVM has been updated to the latest version, and this brings significant
+  changes. Upstream don't release multiple versions targeting different JVMs
+  anymore, so now we only have one GraalVM derivation (`graalvm-ce`). While at
+  first glance the version may seem a downgrade (v22.3.1 -> v21.0.0), the major
+  version is now following the JVM it targets (so this latest version targets
+  JVM 21). Also some products like `llvm-installable-svm` and
+  `native-image-svm` were incorporate to the main GraalVM derivation, so
+  they're included by default.
 
-- GraalPy (`graalCEPackages.graalpy`), TruffleRuby (`graalCEPackages.truffleruby`), GraalJS (`graalCEPackages.graaljs`) and GraalNodeJS (`grallCEPackages.graalnodejs`) are now indepedent from the main GraalVM derivation.
+- GraalPy (`graalCEPackages.graalpy`), TruffleRuby
+  (`graalCEPackages.truffleruby`), GraalJS (`graalCEPackages.graaljs`) and
+  GraalNodeJS (`grallCEPackages.graalnodejs`) are now independent from the main
+  GraalVM derivation.
 
-- The ISC DHCP package and corresponding module have been removed, because they are end of life upstream. See https://www.isc.org/blogs/isc-dhcp-eol/ for details and switch to a different DHCP implementation like kea or dnsmasq.
+- The ISC DHCP package and corresponding module have been removed, because they
+  are EOL upstream. Refer [to this
+  post](https://www.isc.org/blogs/isc-dhcp-eol/) for details and switch to a
+  different DHCP implementation like kea or dnsmasq.
 
-- `prometheus-unbound-exporter` has been replaced by the Let's Encrypt maintained version, since the previous version was archived. This requires some changes to the module configuration, most notable `controlInterface` needs migration
-   towards `unbound.host` and requires either the `tcp://` or `unix://` URI scheme.
+- `prometheus-unbound-exporter` has been replaced by the Let's Encrypt
+  maintained version, since the previous version was archived. This requires
+  some changes to the module configuration, most notable `controlInterface`
+  needs migration towards `unbound.host` and requires either the `tcp://` or
+  `unix://` URI scheme.
 
-- `odoo` now defaults to 16, updated from 15.
+- `odoo` defaults to v16 now, updated from v15.
 
-- `varnish` was upgraded from 7.2.x to 7.4.x, see https://varnish-cache.org/docs/7.3/whats-new/upgrading-7.3.html and https://varnish-cache.org/docs/7.4/whats-new/upgrading-7.4.html for upgrade notes. The current LTS version is still offered as `varnish60`.
+- `varnish` was upgraded from v7.2.x to v7.4.x. Refer to upgrade guides vor
+  [v7.3](https://varnish-cache.org/docs/7.3/whats-new/upgrading-7.3.html) and
+  [v7.4](https://varnish-cache.org/docs/7.4/whats-new/upgrading-7.4.html). The
+  current LTS version is still offered as `varnish60`.
 
-- `util-linux` is now supported on Darwin and is no longer an alias to `unixtools`. Use the `unixtools.util-linux` package for access to the Apple variants of the utilities.
+- `util-linux` is now supported on Darwin and is no longer an alias to
+  `unixtools`. Use the `unixtools.util-linux` package for access to the Apple
+  variants of the utilities.
 
 - `services.keyd` changed API. Now you can create multiple configuration files.
 
-- `baloo`, the file indexer/search engine used by KDE now has a patch to prevent files from constantly being reindexed when the device ids of the their underlying storage changes. This happens frequently when using btrfs or LVM. The patch has not yet been accepted upstream but it provides a significantly improved experience. When upgrading, reset baloo to get a clean index: `balooctl disable ; balooctl purge ; balooctl enable`.
-
-- The `vlock` program from the `kbd` package has been moved into its own package output and should now be referenced explicitly as `kbd.vlock` or replaced with an alternative such as the standalone `vlock` package or `physlock`.
-
-- `fileSystems.<name>.autoFormat` now uses `systemd-makefs`, which does not accept formatting options. Therefore, `fileSystems.<name>.formatOptions` has been removed.
-
-- `fileSystems.<name>.autoResize` now uses `systemd-growfs` to resize the file system online in stage 2. This means that `f2fs` and `ext2` can no longer be auto resized, while `xfs` and `btrfs` now can be.
-
-- `fuse3` has been updated from 3.11.0 to 3.16.2; see [ChangeLog.rst](https://github.com/libfuse/libfuse/blob/fuse-3.16.2/ChangeLog.rst#libfuse-3162-2023-10-10) for an overview of the changes.
-
-  Unsupported mount options are no longer silently accepted [(since 3.15.0)](https://github.com/libfuse/libfuse/blob/fuse-3.16.2/ChangeLog.rst#libfuse-3150-2023-06-09). The [affected mount options](https://github.com/libfuse/libfuse/commit/dba6b3983af34f30de01cf532dff0b66f0ed6045) are: `atime`, `diratime`, `lazytime`, `nolazytime`, `relatime`, `norelatime`, `strictatime`.
+- `baloo`, the file indexer and search engine used by KDE now has a patch to
+  prevent files from constantly being reindexed when the device IDs of the
+  their underlying storage change. This happens frequently when using btrfs or
+  LVM. The patch has not yet been accepted upstream but it provides a
+  significantly improved experience. When upgrading, reset baloo to get a clean
+  index: `balooctl disable ; balooctl purge ; balooctl enable`.
+
+- The `vlock` program from the `kbd` package has been moved into its own
+  package output and should now be referenced explicitly as `kbd.vlock` or
+  replaced with an alternative such as the standalone `vlock` package or
+  `physlock`.
+
+- `fileSystems.<name>.autoFormat` now uses `systemd-makefs`, which does not
+  accept formatting options. Therefore, `fileSystems.<name>.formatOptions` has
+  been removed.
+
+- `fileSystems.<name>.autoResize` uses `systemd-growfs` to resize the file
+  system online in Stage 2 now. This means that `f2fs` and `ext2` can no longer
+  be auto resized, while `xfs` and `btrfs` now can be.
+
+- `fuse3` has been updated from v3.11.0 to v3.16.2. Refer to the
+  [changelog](https://github.com/libfuse/libfuse/blob/fuse-3.16.2/ChangeLog.rst#libfuse-3162-2023-10-10)
+  for an overview of the changes.
+
+  Unsupported mount options are no longer silently accepted [(since
+  3.15.0)](https://github.com/libfuse/libfuse/blob/fuse-3.16.2/ChangeLog.rst#libfuse-3150-2023-06-09).
+  The [affected mount
+  options](https://github.com/libfuse/libfuse/commit/dba6b3983af34f30de01cf532dff0b66f0ed6045)
+  are: `atime`, `diratime`, `lazytime`, `nolazytime`, `relatime`, `norelatime`,
+  `strictatime`.
 
   For example,
 
   ```bash
-  $ sshfs 127.0.0.1:/home/test/testdir /home/test/sshfs_mnt -o atime`
+  $ sshfs 127.0.0.1:/home/test/testdir /home/test/sshfs_mnt -o atime
   ```
 
-  would previously terminate successfully with the mount point established, now it outputs the error message ``fuse: unknown option(s): `-o atime'`` and terminates with exit status 1.
-
-- `nixos-rebuild {switch,boot,test,dry-activate}` now runs the system activation inside `systemd-run`, creating an ephemeral systemd service and protecting the system switch against issues like network disconnections during remote (e.g. SSH) sessions. This has the side effect of running the switch in an isolated environment, that could possible break post-switch scripts that depends on things like environment variables being set. If you want to opt-out from this behavior for now, you may set the `NIXOS_SWITCH_USE_DIRTY_ENV` environment variable before running `nixos-rebuild`. However, keep in mind that this option will be removed in the future.
-
-- The `services.vaultwarden.config` option default value was changed to make Vaultwarden only listen on localhost, following the [secure defaults for most NixOS services](https://github.com/NixOS/nixpkgs/issues/100192).
-
-- `services.lemmy.settings.federation` was removed in 0.17.0 and no longer has any effect. To enable federation, the hostname must be set in the configuration file and then federation must be enabled in the admin web UI. See the [release notes](https://github.com/LemmyNet/lemmy/blob/c32585b03429f0f76d1e4ff738786321a0a9df98/RELEASES.md#upgrade-instructions) for more details.
-
-- `pict-rs` was upgraded from 0.3 to 0.4 and contains an incompatible database & configuration change. To upgrade on systems with `stateVersion = "23.05";` or older follow the migration steps from https://git.asonix.dog/asonix/pict-rs#user-content-0-3-to-0-4-migration-guide and set `services.pict-rs.package = pkgs.pict-rs;`.
+  would previously terminate successfully with the mount point established, now
+  it outputs the error message ``fuse: unknown option(s): `-o atime'`` and
+  terminates with exit status 1.
+
+- `nixos-rebuild {switch,boot,test,dry-activate}` runs the system
+  activation inside `systemd-run` now, creating an ephemeral systemd service
+  and protecting the system switch against issues like network disconnections
+  during remote (e.g. SSH) sessions. This has the side effect of running the
+  switch in an isolated environment, that could possible break post-switch
+  scripts that depends on things like environment variables being set. If you
+  want to opt-out from this behavior for now, you may set the
+  `NIXOS_SWITCH_USE_DIRTY_ENV` environment variable before running
+  `nixos-rebuild`. However, keep in mind that this option will be removed in
+  the future.
+
+- The `services.vaultwarden.config` option default value was changed to make
+  Vaultwarden only listen on localhost, following the [secure defaults for most
+  NixOS services](https://github.com/NixOS/nixpkgs/issues/100192).
+
+- `services.lemmy.settings.federation` was removed in v0.17.0 and no longer has
+  any effect. To enable federation, the hostname must be set in the
+  configuration file and then federation must be enabled in the admin web UI.
+  Refer to the [release
+  notes](https://github.com/LemmyNet/lemmy/blob/c32585b03429f0f76d1e4ff738786321a0a9df98/RELEASES.md#upgrade-instructions)
+  for more details.
+
+- `pict-rs` was upgraded from v0.3 to v0.4 and contains an incompatible database
+  & configuration change. To upgrade on systems with `stateVersion = "23.05";`
+  or older follow the migration steps from
+  https://git.asonix.dog/asonix/pict-rs#user-content-0-3-to-0-4-migration-guide
+  and set `services.pict-rs.package = pkgs.pict-rs;`.
+
+- The following packages in `haskellPackages` have a separate bin output now:
+  `cabal-fmt`, `calligraphy`, `eventlog2html`, `ghc-debug-brick`, `hindent`,
+  `nixfmt`, `releaser`. This means you need to replace e.g.
+  `"${pkgs.haskellPackages.nixfmt}/bin/nixfmt"` with `"${lib.getBin
+  pkgs.haskellPackages.nixfmt}/bin/nixfmt"` or `"${lib.getExe
+  pkgs.haskellPackages.nixfmt}"`. The binaries also won’t be in scope if you
+  rely on them being installed e.g. via `ghcWithPackages`.
+  `environment.packages` picks the `bin` output automatically, so for normal
+  installation no intervention is required. Also, toplevel attributes like
+  `pkgs.nixfmt` are not impacted negatively by this change.
+
+- `spamassassin` no longer supports the `Hashcash` module. The module needs to
+  be removed from the `loadplugin` list if it was copied over from the default
+  `initPreConf` option.
+
+- `nano` was removed from `environment.defaultPackages`. To not leave systems
+  without a editor, now `programs.nano.enable` is enabled by default.
+
+- `programs.nano.nanorc` and `programs.nano.syntaxHighlight` no longer have an
+  effect unless `programs.nano.enable` is set to true which is the default.
+
+- `services.outline.sequelizeArguments` has been removed, as `outline` no
+  longer executes database migrations via the `sequelize` cli.
+
+- The binary of the package `cloud-sql-proxy` has changed from
+  `cloud_sql_proxy` to `cloud-sql-proxy`.
+
+- The module `services.apache-kafka` was largely rewritten and has certain
+  breaking changes. To be precise, this means that the following things have
+  changed:
+  - Most settings have been migrated to
+    [services.apache-kafka.settings](#opt-services.apache-kafka.settings).
+    - Care must be taken when adapting an existing cluster to these changes,
+      see [](#module-services-apache-kafka-migrating-to-settings).
+  - By virtue of being less opinionated, it is now possible to use the module
+    to run Apache Kafka in KRaft mode instead of Zookeeper mode.
+    - [A few options](#module-services-apache-kafka-kraft) have been added to
+      assist in this mode.
+
+- Garage has been upgraded to v0.9.x. `services.garage.package` needs to be
+  explicitly set now, so version upgrades can be done in a controlled fashion.
+  For this, we expose `garage_x_y` attributes which can be set here.
+
+- `voms` and `xrootd` now moves the `$out/etc` content to the `$etc` output
+  instead of `$out/etc.orig`, when input argument `externalEtc` is not `null`.
+
+- The `woodpecker-*` CI packages have been updated to v1.0.0. This release is
+  wildly incompatible with the v0.15.x versions that were previously packaged.
+  Refer to [upstream's
+  documentation](https://woodpecker-ci.org/docs/next/migrations#100) to learn
+  how to update your CI configurations.
+
+- Meilisearch was updated from v1.3.1 to v1.5.0. The update has breaking
+  changes about backslashes and filtering. Refer to the [release
+  announcement](https://blog.meilisearch.com/v1-4-release/) for more
+  details.
+
+- The Caddy module gained a new option named `services.caddy.enableReload`
+  which is enabled by default. It allows reloading the service instead of
+  restarting it, if only a config file has changed. This option must be
+  disabled if you have turned off the [Caddy admin
+  API](https://caddyserver.com/docs/caddyfile/options#admin). If you keep this
+  option enabled, you should consider setting
+  [`grace_period`](https://caddyserver.com/docs/caddyfile/options#grace-period)
+  to a non-infinite value to prevent Caddy from delaying the reload
+  indefinitely.
+
+- mdraid support is optional now. This reduces initramfs size and prevents the
+  potentially undesired automatic detection and activation of software RAID
+  pools. It is disabled by default in new configurations (determined by
+  `stateVersion`), but the appropriate settings will be generated by
+  `nixos-generate-config` when installing to a software RAID device, so the
+  standard installation procedure should be unaffected. If you have custom
+  configs relying on mdraid, ensure that you use `stateVersion` correctly or
+  set `boot.swraid.enable` manually. On systems with an updated `stateVersion`
+  we now also emit warnings if `mdadm.conf` does not contain the minimum
+  required configuration necessary to run the dynamically enabled monitoring
+  daemons.
+
+- The `go-ethereum` package has been updated to v1.12.0. This drops support for
+  proof-of-work. Its GraphQL API now encodes all numeric values as hex strings
+  and the GraphQL UI is updated to v2.0. The default database has changed from
+  `leveldb` to `pebble` but `leveldb` can be forced with the
+  --db.engine=leveldb flag. The `checkpoint-admin` command was [removed along
+  with trusted
+  checkpoints](https://github.com/ethereum/go-ethereum/pull/27147).
+
+- The `aseprite-unfree` package has been upgraded from v1.2.16.3 to v1.2.40.
+  The free version of aseprite has been dropped because it is EOL and the
+  package attribute now points to the unfree version. A maintained fork of the
+  last free version of Aseprite, named 'LibreSprite', is available in the
+  `libresprite` package.
+
+- The default `kops` version is v1.28.0 now and support for v1.25 and older have
+  been dropped.
+
+- `pharo` has been updated to latest stable v10.0.8, which is compatible with
+  the latest stable and oldstable images (Pharo 10 and 11). The VM in question
+  is the 64bit Spur. The 32bit version has been dropped due to lack of
+  maintenance. The Cog VM has been deleted because it is severily outdated.
+  Finally, the `pharo-launcher` package has been deleted because it was not
+  compatible with the newer VM, and due to lack of maintenance.
+
+- Emacs mainline v29 was introduced. This new version includes many major
+  additions, most notably `tree-sitter` support (enabled by default) and
+  the pgtk variant (useful for Wayland users), which is available under the
+  attribute `emacs29-pgtk`.
 
-- The following packages in `haskellPackages` have now a separate bin output: `cabal-fmt`, `calligraphy`, `eventlog2html`, `ghc-debug-brick`, `hindent`, `nixfmt`, `releaser`. This means you need to replace e.g. `"${pkgs.haskellPackages.nixfmt}/bin/nixfmt"` with `"${lib.getBin pkgs.haskellPackages.nixfmt}/bin/nixfmt"` or `"${lib.getExe pkgs.haskellPackages.nixfmt}"`. The binaries also won’t be in scope if you rely on them being installed e.g. via `ghcWithPackages`. `environment.packages` picks the `bin` output automatically, so for normal installation no intervention is required. Also, toplevel attributes like `pkgs.nixfmt` are not impacted negatively by this change.
-
-- `spamassassin` no longer supports the `Hashcash` module. The module needs to be removed from the `loadplugin` list if it was copied over from the default `initPreConf` option.
-
-- `nano` was removed from `environment.defaultPackages`. To not leave systems without a editor, now `programs.nano.enable` is enabled by default.
-
-- `programs.nano.nanorc` and `programs.nano.syntaxHighlight` no longer have an effect unless `programs.nano.enable` is set to true which is the default.
-
-- `services.outline.sequelizeArguments` has been removed, as `outline` no longer executes database migrations via the `sequelize` cli.
-
-- The binary of the package `cloud-sql-proxy` has changed from `cloud_sql_proxy` to `cloud-sql-proxy`.
-
-- The module `services.apache-kafka` was largely rewritten and has certain breaking changes. To be precise, this means that the following things have changed:
-
-  - Most settings have been migrated to [services.apache-kafka.settings](#opt-services.apache-kafka.settings).
-    - Care must be taken when adapting an existing cluster to these changes, see [](#module-services-apache-kafka-migrating-to-settings).
-  - By virtue of being less opinionated, it is now possible to use the module to run Apache Kafka in KRaft mode instead of Zookeeper mode.
-    - [A few options](#module-services-apache-kafka-kraft) have been added to assist in this mode.
-
-- Garage has been upgraded to 0.9.x. `services.garage.package` now needs to be explicitly set, so version upgrades can be done in a controlled fashion. For this, we expose `garage_x_y` attributes which can be set here.
-
-- `voms` and `xrootd` now moves the `$out/etc` content to the `$etc` output instead of `$out/etc.orig`, when input argument `externalEtc` is not `null`.
-
-- The `woodpecker-*` CI packages have been updated to 1.0.0. This release is wildly incompatible with the 0.15.X versions that were previously packaged. Please read [upstream's documentation](https://woodpecker-ci.org/docs/next/migrations#100) to learn how to update your CI configurations.
-
-- Meilisearch was updated from 1.3.1 to 1.5.0. The update has breaking changes about backslashes and filtering. See the [release announcement](https://blog.meilisearch.com/v1-4-release/) for more information.
-
-- The Caddy module gained a new option named `services.caddy.enableReload` which is enabled by default. It allows reloading the service instead of restarting it, if only a config file has changed. This option must be disabled if you have turned off the [Caddy admin API](https://caddyserver.com/docs/caddyfile/options#admin). If you keep this option enabled, you should consider setting [`grace_period`](https://caddyserver.com/docs/caddyfile/options#grace-period) to a non-infinite value to prevent Caddy from delaying the reload indefinitely.
-
-- mdraid support is now optional. This reduces initramfs size and prevents the potentially undesired automatic detection and activation of software RAID pools. It is disabled by default in new configurations (determined by `stateVersion`), but the appropriate settings will be generated by `nixos-generate-config` when installing to a software RAID device, so the standard installation procedure should be unaffected. If you have custom configs relying on mdraid, ensure that you use `stateVersion` correctly or set `boot.swraid.enable` manually. On systems with an updated `stateVersion` we now also emit warnings if `mdadm.conf` does not contain the minimum required configuration necessary to run the dynamically enabled monitoring daemons.
-
-- The `go-ethereum` package has been updated to v1.12.0. This drops support for proof-of-work. Its GraphQL API now encodes all numeric values as hex strings and the GraphQL UI is updated to version 2.0. The default database has changed from `leveldb` to `pebble` but `leveldb` can be forced with the --db.engine=leveldb flag. The `checkpoint-admin` command was [removed along with trusted checkpoints](https://github.com/ethereum/go-ethereum/pull/27147).
-
-- The `aseprite-unfree` package has been upgraded from 1.2.16.3 to 1.2.40. The free version of aseprite has been dropped because it is EOL and the package attribute now points to the unfree version. A maintained fork of the last free version of Aseprite, named 'LibreSprite', is available in the `libresprite` package.
+- Emacs macport version 29 was introduced.
 
-- The default `kops` version is now 1.28.0 and support for 1.25 and older has been dropped.
+- The option `services.networking.networkmanager.enableFccUnlock` was removed
+  in favor of `networking.networkmanager.fccUnlockScripts`, which allows
+  specifying unlock scripts explicitly. The previous option enabled all unlock
+  scripts bundled with ModemManager, which is risky, and didn't allow using
+  vendor-provided unlock scripts at all.
+
+- The `html-proofer` package has been updated from major version 3 to major
+  version 5, which includes [breaking
+  changes](https://github.com/gjtorikian/html-proofer/blob/v5.0.8/UPGRADING.md).
+
+- `kratos` has been updated from v0.10.1 to the first stable v1.0.0, please
+  read the [v0.10.1 to
+  v0.11.0](https://github.com/ory/kratos/releases/tag/v0.11.0), [v0.11.0 to
+  v0.11.1](https://github.com/ory/kratos/releases/tag/v0.11.1), [v0.11.1 to
+  v0.13.0](https://github.com/ory/kratos/releases/tag/v0.13.0) and [v0.13.0 to
+  v1.0.0](https://github.com/ory/kratos/releases/tag/v1.0.0) upgrade guides.
+  The most notable breaking change is the introduction of one-time passwords
+  (`code`) and update of the default recovery strategy from `link` to `code`.
+
+- The `hail` module was removed, as `hail` was unmaintained since 2017.
+
+- Package `noto-fonts-emoji` was renamed to `noto-fonts-color-emoji`. Refer to
+  [PR #221181](https://github.com/NixOS/nixpkgs/issues/221181) for more
+  details.
+
+- Package `cloud-sql-proxy` was renamed to `google-cloud-sql-proxy` as it
+  cannot be used with other cloud providers.
+
+- 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.
+
+- Package `pash` was removed due to being archived upstream. Use `powershell`
+  as an alternative.
+
+- The option `services.plausible.releaseCookiePath` has been removed. Plausible
+  does not use any distributed Erlang features, and does not plan to (refer to
+  [discussion](https://github.com/NixOS/nixpkgs/pull/130297#issuecomment-1805851333)),
+  Thus NixOS disables them now , and the Erlang cookie becomes unnecessary. You
+  may delete the file that `releaseCookiePath` was set to.
+
+- `security.sudo.extraRules` includes `root`'s default rule now, with ordering
+  priority 400. This is functionally identical for users not specifying rule
+  order, or relying on `mkBefore` and `mkAfter`, but may impact users calling
+  `mkOrder n` with n ≤ 400.
 
-- `pharo` has been updated to latest stable (PharoVM 10.0.8), which is compatible with the latest stable and oldstable images (Pharo 10 and 11). The VM in question is the 64bit Spur. The 32bit version has been dropped due to lack of maintenance. The Cog VM has been deleted because it is severily outdated. Finally, the `pharo-launcher` package has been deleted because it was not compatible with the newer VM, and due to lack of maintenance.
+- X keyboard extension (XKB) options have been reorganized into a single
+  attribute set, `services.xserver.xkb`. Specifically,
+  `services.xserver.layout` is `services.xserver.xkb.layout` now,
+  `services.xserver.extraLayouts` is `services.xserver.xkb.extraLayouts` now,
+  `services.xserver.xkbModel` is `services.xserver.xkb.model` now,
+  `services.xserver.xkbOptions` is `services.xserver.xkb.options` now ,
+  `services.xserver.xkbVariant` is `services.xserver.xkb.variant` now, and
+  `services.xserver.xkbDir` is `services.xserver.xkb.dir` now.
+
+- `networking.networkmanager.firewallBackend` was removed as NixOS is now using
+  iptables-nftables-compat even when using iptables, therefore Networkmanager
+  uses the nftables backend unconditionally now.
+
+- `rome` was removed because it is no longer maintained and is succeeded by
+  `biome`.
+
+- The `prometheus-knot-exporter` was migrated to a version maintained by
+  CZ.NIC. Various metric names have changed, so checking existing rules is
+  recommended.
+
+- The `services.mtr-exporter.target` has been removed in favor of
+  `services.mtr-exporter.jobs` which allows specifying multiple targets.
+
+- `blender-with-packages` has been deprecated in favor of
+  `blender.withPackages`, for example `blender.withPackages (ps: [ps.bpycv])`.
+  It behaves similarly to `python3.withPackages`.
+
+- Setting `nixpkgs.config` options while providing an external `pkgs` instance
+  will now raise an error instead of silently ignoring the options. NixOS
+  modules no longer set `nixpkgs.config` to accommodate this. This specifically
+  affects `services.locate`,
+  `services.xserver.displayManager.lightdm.greeters.tiny` and
+  `programs.firefox` NixOS modules. No manual intervention should be required
+  in most cases, however, configurations relying on those modules affecting
+  packages outside the system environment should switch to explicit overlays.
+
+- `privacyidea` (and the corresponding `privacyidea-ldap-proxy`) has been
+  removed from nixpkgs because it has severely outdated dependencies that
+  became unmaintainable with nixpkgs' python package-set.
+
+- `dagger` was removed because using a package called `dagger` and packaging it
+  from source violates their trademark policy.
 
-- Emacs mainline version 29 was introduced. This new version includes many major additions, most notably `tree-sitter` support (enabled by default) and the pgtk variant (useful for Wayland users), which is available under the attribute `emacs29-pgtk`.
+- `win-virtio` package was renamed to `virtio-win` to be consistent with the upstream package name.
 
-- Emacs macport version 29 was introduced.
+- `ps3netsrv` has been replaced with the webman-mod fork, the executable has
+  been renamed from `ps3netsrv++` to `ps3netsrv` and cli parameters have
+  changed.
 
-- The option `services.networking.networkmanager.enableFccUnlock` was removed in favor of `networking.networkmanager.fccUnlockScripts`, which allows specifying unlock scripts explicitly. The previous option enabled all unlock scripts bundled with ModemManager, which is risky, and didn't allow using vendor-provided unlock scripts at all.
+- `ssm-agent` package and module were renamed to `amazon-ssm-agent` to be
+  consistent with the upstream package name.
 
-- The `html-proofer` package has been updated from major version 3 to major version 5, which includes [breaking changes](https://github.com/gjtorikian/html-proofer/blob/v5.0.8/UPGRADING.md).
+- `services.kea.{ctrl-agent,dhcp-ddns,dhcp,dhcp6}` now use separate runtime
+  directories instead of `/run/kea` to work around the runtime directory being
+  cleared on service start.
 
-- `kratos` has been updated from 0.10.1 to the first stable version 1.0.0, please read the [0.10.1 to 0.11.0](https://github.com/ory/kratos/releases/tag/v0.11.0), [0.11.0 to 0.11.1](https://github.com/ory/kratos/releases/tag/v0.11.1), [0.11.1 to 0.13.0](https://github.com/ory/kratos/releases/tag/v0.13.0) and [0.13.0 to 1.0.0](https://github.com/ory/kratos/releases/tag/v1.0.0) upgrade guides. The most notable breaking change is the introduction of one-time passwords (`code`) and update of the default recovery strategy from `link` to `code`.
+- `mkDerivation` rejects MD5 hashes now.
 
-- The `hail` NixOS module was removed, as `hail` was unmaintained since 2017.
+- The `junicode` font package has been updated to [major
+  v2](https://github.com/psb1558/Junicode-font/releases/tag/v2.001), which is
+  a font family now. In particular, plain `Junicode.ttf` no longer exists. In
+  addition, TrueType font files are now placed in `font/truetype` instead of
+  `font/junicode-ttf`; this change does not affect use via `fonts.packages`
+  option.
 
-- Package `noto-fonts-emoji` was renamed to `noto-fonts-color-emoji`;
-  see [#221181](https://github.com/NixOS/nixpkgs/issues/221181).
+- The `prayer` package as well as `services.prayer` have been removed because
+  it's been unmaintained for several years and the author's website has
+  vanished.
 
-- Package `cloud-sql-proxy` was renamed to `google-cloud-sql-proxy` as it cannot be used with other cloud providers.;
+- The `chrony` NixOS module now tracks the real-time clock drift from the
+  system clock with `rtcfile` and automatically adjusts it with `rtcautotrim`
+  when it exceeds the maximum error specified in
+  `services.chrony.autotrimThreshold` (defaults to 30 seconds). If you enabled
+  `rtcsync` in `extraConfig`, you should remove RTC related options from
+  `extraConfig`. If you do not want chrony configured to keep the RTC in check,
+  you can set `services.chrony.enableRTCTrimming = false;`.
 
-- 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.
+- `trilium-desktop` and `trilium-server` have been updated to
+  [v0.61](https://github.com/zadam/trilium/releases/tag/v0.61.12). For existing
+  installations, upgrading to this version is supported only after running
+  v0.60.x at least once. If you are still on an older version, make sure to
+  update to v0.60 (available in NixOS 23.05) first and only then to v0.61
+  (available in NixOS 23.11).
 
-- Package `pash` was removed due to being archived upstream. Use `powershell` as an alternative.
+- Cassandra now defaults to v4.x, updated from v3.11.x.
 
-- The option `services.plausible.releaseCookiePath` has been removed: Plausible does not use any distributed Erlang features, and does not plan to (see [discussion](https://github.com/NixOS/nixpkgs/pull/130297#issuecomment-1805851333)), so NixOS now disables them, and the Erlang cookie becomes unnecessary. You may delete the file that `releaseCookiePath` was set to.
 
-- `security.sudo.extraRules` now includes `root`'s default rule, with ordering
-  priority 400. This is functionally identical for users not specifying rule
-  order, or relying on `mkBefore` and `mkAfter`, but may impact users calling
-  `mkOrder n` with n ≤ 400.
+- FoundationDB now defaults to major version 7.
 
-- X keyboard extension (XKB) options have been reorganized into a single attribute set, `services.xserver.xkb`. Specifically, `services.xserver.layout` is now `services.xserver.xkb.layout`, `services.xserver.extraLayouts` is now `services.xserver.xkb.extraLayouts`, `services.xserver.xkbModel` is now `services.xserver.xkb.model`, `services.xserver.xkbOptions` is now `services.xserver.xkb.options`, `services.xserver.xkbVariant` is now `services.xserver.xkb.variant`, and `services.xserver.xkbDir` is now `services.xserver.xkb.dir`.
+- [glibc](https://www.gnu.org/software/libc/) has been updated from v2.37 to
+  v2.38. Refer to the [the release
+  notes](https://sourceware.org/glibc/wiki/Release/2.38) for more details.
 
-- `networking.networkmanager.firewallBackend` was removed as NixOS is now using iptables-nftables-compat even when using iptables, therefore Networkmanager now uses the nftables backend unconditionally.
+- `linuxPackages_testing_bcachefs` is now soft-deprecated by
+  `linuxPackages_testing`.
+  - Please consider changing your NixOS configuration's `boot.kernelPackages`
+    to `linuxPackages_testing` until a stable kernel with bcachefs support is
+    released.
 
-- `rome` was removed because it is no longer maintained and is succeeded by `biome`.
+- PostgreSQL now defaults to major version 15.
 
-- The `prometheus-knot-exporter` was migrated to a version maintained by CZ.NIC. Various metric names have changed, so checking existing rules is recommended.
+- All [ROCm](https://rocm.docs.amd.com/en/latest/) packages have been updated
+  to v5.7.0.
+  - [ROCm](https://rocm.docs.amd.com/en/latest/) package attribute sets are
+    versioned: `rocmPackages` -> `rocmPackages_5`.
+
+- [systemd](https://systemd.io) has been updated from v253 to v254, refer to
+  [the release
+  notes](https://github.com/systemd/systemd/blob/v254/NEWS#L3-L659) for more
+  details.
+    - `boot.resumeDevice` **must be specified** when hibernating if not in EFI
+      mode.
+    - systemd may warn your system about the permissions of your ESP partition
+      (often `/boot`), this warning can be ignored for now, we are looking into
+      a satisfying solution regarding this problem.
+    - Updating with `nixos-rebuild boot` and rebooting is recommended, since in
+      some rare cases the `nixos-rebuild switch` into the new generation on a
+      live system might fail due to missing mount units.
+
+- If the user has a custom shell enabled via `users.users.${USERNAME}.shell =
+  ${CUSTOMSHELL}`, the assertion will require them to also set
+  `programs.${CUSTOMSHELL}.enable = true`. This is generally safe behavior, but
+  for anyone needing to opt out from the check
+  `users.users.${USERNAME}.ignoreShellProgramCheck = true` will do the job.
+
+- `yarn-berry` has been updated to v4.0.1. This means that NodeJS versions less
+  v18.12 are no longer supported by it. Refer to the [upstream
+  changelog](https://github.com/yarnpkg/berry/blob/master/CHANGELOG.md) for
+  more details.
+
+- GNOME has been updated to v45. Refer to the [release
+  notes](https://release.gnome.org/45/) for more details. Notably, Loupe has
+  replaced Eye of GNOME as the default image viewer, Snapshot has replaced
+  Cheese as the default camera application, and Photos will no longer be
+  installed.
+
+- The module [services.ankisyncd](#opt-services.ankisyncd.package) has been
+  switched to
+  [anki-sync-server-rs](https://github.com/ankicommunity/anki-sync-server-rs).
+  The former version written in Python was difficult to update, did not receive
+  updates in a while, and did not support recent versions of Anki.
+
+  Unfortunately all servers supporting new clients do not support the older
+  sync protocol that was used in the old server. This includes newer version of
+  anki-sync-server, Anki's built in sync server and this new Rust package. Thus
+  old clients will also need updating. In particular nixpkgs's Anki package is
+  also being updated in this release.
+
+  The module update takes care of the new config syntax. The data itself (i.e.
+  user login and card information) is compatible. Thus users of the module will
+  be able to simply log in again after updating both client and server without
+  any extra action needed to be taken.
+
+- The argument `vendorSha256` of `buildGoModule` is deprecated. Use
+  `vendorHash` instead. Refer to [PR
+  \#259999](https://github.com/NixOS/nixpkgs/pull/259999)) for more details.
+
+- `go-modules` in `buildGoModule` attrs has been renamed to `goModules`.
+
+- The package `cawbird` is dropped from nixpkgs. It broke by the Twitter API
+  closing down and has been abandoned upstream.
+
+- The Cinnamon module now enables XDG desktop integration by default. If you
+  are experiencing collisions related to xdg-desktop-portal-gtk you can safely
+  remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your
+  NixOS configuration.
+
+- GNOME, Pantheon, Cinnamon modules no longer force Qt applications to use
+  Adwaita style. This implemantion  was buggy and is no longer maintained
+  upstream. Specifically, Cinnamon defaults to the gtk2 style instead now,
+  following the default in Linux Mint). If you still want Adwaita used, you may
+  add the following options to your configuration. Please be aware, that it
+  will probably be removed eventually.
 
-- The `services.mtr-exporter.target` has been removed in favor of `services.mtr-exporter.jobs` which allows specifying multiple targets.
+  ```nix
+  qt = {
+    enable = true;
+    platformTheme = "gnome";
+    style = "adwaita";
+  };
+  ```
 
-- `blender-with-packages` has been deprecated in favor of `blender.withPackages`, for example `blender.withPackages (ps: [ps.bpycv])`. It behaves similarly to `python3.withPackages`.
+- DocBook option documentation is no longer supported, all module documentation
+  now uses Markdown.
 
-- Setting `nixpkgs.config` options while providing an external `pkgs` instance will now raise an error instead of silently ignoring the options. NixOS modules no longer set `nixpkgs.config` to accomodate this. This specifically affects `services.locate`, `services.xserver.displayManager.lightdm.greeters.tiny` and `programs.firefox` NixOS modules. No manual intervention should be required in most cases, however, configurations relying on those modules affecting packages outside the system environment should switch to explicit overlays.
+- Docker defaults to v24 now, as 20.10 is stopping to receive security updates
+  and bug fixes after [December 10,
+  2023](https://github.com/moby/moby/discussions/45104).
 
-- `service.borgmatic.settings.location` and `services.borgmatic.configurations.<name>.location` are deprecated, please move your options out of sections to the global scope.
+- Elixir defaults to v1.15 now. Refer to their
+  [changelog](https://elixir-lang.org/blog/2023/06/19/elixir-v1-15-0-released/)
+  for more details.
 
-- `privacyidea` (and the corresponding `privacyidea-ldap-proxy`) has been removed from nixpkgs because it has severely outdated dependencies that became unmaintainable with nixpkgs' python package-set.
+- The `extend` function of `llvmPackages` has been removed due it coming from
+  the `tools` attrset thus only extending the `tool` attrset. A possible
+  replacement is to construct the set from `libraries` and `tools`, or patch
+  nixpkgs.
 
-- `dagger` was removed because using a package called `dagger` and packaging it from source violates their trademark policy.
+- `ffmpeg` defaults to `ffmpeg_6` now, upgrading from `ffmpeg_5`.
 
-- `win-virtio` package was renamed to `virtio-win` to be consistent with the upstream package name.
+- `fontconfig` defaults to using greyscale antialiasing now. Previously
+  subpixel antialiasing was used because of a [recommendation from one of the
+  downstreams](https://gitlab.freedesktop.org/fontconfig/fontconfig/-/issues/337).
+  You can change this value by configuring
+  [](#opt-fonts.fontconfig.subpixel.rgba) accordingly.
 
-- `ps3netsrv` has been replaced with the webman-mod fork, the executable has been renamed from `ps3netsrv++` to `ps3netsrv` and cli parameters have changed.
+- The `fonts.fonts` and `fonts.enableDefaultFonts` options have been renamed to
+  `fonts.packages` and `fonts.enableDefaultPackages` respectively.
 
-- `ssm-agent` package and module were renamed to `amazon-ssm-agent` to be consistent with the upstream package name.
+- `services.hedgedoc` has been heavily refactored, reducing the amount of
+  declared options in the module. Most of the options should still work without
+  any changes to the configuration. Some options have been deprecated, as they
+  no longer have any effect. Refer to [PR
+  #244941](https://github.com/NixOS/nixpkgs/pull/244941) for more details.
 
-- `services.kea.{ctrl-agent,dhcp-ddns,dhcp,dhcp6}` now use separate runtime directories instead of `/run/kea` to work around the runtime directory being cleared on service start.
+- `jq` was updated to v1.7. This is its [first release in 5
+  years](https://github.com/jqlang/jq/releases/tag/jq-1.7).
 
-- `mkDerivation` now rejects MD5 hashes.
+- [`lib.attrsets.foldlAttrs`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.attrsets.foldlAttrs)
+  now always evaluates the initial accumulator argument first.
 
-- The `junicode` font package has been updated to [major version 2](https://github.com/psb1558/Junicode-font/releases/tag/v2.001), which is now a font family. In particular, plain `Junicode.ttf` no longer exists. In addition, TrueType font files are now placed in `font/truetype` instead of `font/junicode-ttf`; this change does not affect use via `fonts.packages` NixOS option.
+- [`lib.lists.foldl'`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.foldl-prime)
+  now always evaluates the initial accumulator argument first. If you depend on
+  the lazier behavior, consider using
+  [`lib.lists.foldl`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.foldl)
+  or
+  [`builtins.foldl'`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-foldl')
+  instead.
 
-- The `prayer` package as well as `services.prayer` have been removed because it's been unmaintained for several years and the author's website has vanished.
+-  Now `magma` defaults to `magma-hip` instead of `magma-cuda`. It also
+   respects the `config.cudaSupport` and `config.rocmSupport` options.
 
-- The `chrony` NixOS module now tracks the Real-Time Clock drift from the System Clock with `rtcfile` and automatically adjusts it with `rtcautotrim` when it exceeds the maximum error specified in `services.chrony.autotrimThreshold` (default 30 seconds). If you enabled `rtcsync` in `extraConfig`, you should remove RTC related options from `extraConfig`. If you do not want chrony configured to keep the RTC in check, you can set `services.chrony.enableRTCTrimming = false;`
+- The MariaDB C client library was upgraded from v3.2.x to v3.3.x. Refer to the
+  [upstream release
+  notes](https://mariadb.com/kb/en/mariadb-connector-c-33-release-notes/) for
+  more details.
 
-- `trilium-desktop` and `trilium-server` have been updated to [v0.61](https://github.com/zadam/trilium/releases/tag/v0.61.12). For existing installations, upgrading to this version is supported only after running v0.60.X at least once. If you are still on an older version, make sure to update to v0.60 (available in NixOS 23.05) first and only then to v0.61 (available in NixOS 23.11).
+- Mattermost has been upgraded to extended support version 8.1 as the previously
+  packaged extended support version 7.8 is [reaching end-of-life](https://docs.mattermost.com/upgrade/extended-support-release.html).
+  Migration may take some time, refer to the [changelog](https://docs.mattermost.com/install/self-managed-changelog.html#release-v8-1-extended-support-release)
+  and [important upgrade notes](https://docs.mattermost.com/upgrade/important-upgrade-notes.html).
 
-## Other Notable Changes {#sec-release-23.11-notable-changes}
+- The `netdata` package disables cloud support by default now. To enable it use the `netdataCloud` package.
 
-- A new option `system.switch.enable` was added. By default, this is option is
-  enabled. Disabling it makes the system unable to be reconfigured via
-  `nixos-rebuild`. This is good for image based appliances where updates are
-  handled outside the image.
+- `networking.nftables` is no longer flushing all rulesets on every reload.
+  Use `networking.nftables.flushRuleset = true;` to enable the previous behaviour.
 
-- The Cinnamon module now enables XDG desktop integration by default. If you are experiencing collisions related to xdg-desktop-portal-gtk you can safely remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your NixOS configuration.
+- Node.js v14, v16 has been removed as they were end of life. Any dependent packages that contributors were not able to reasonably upgrade were dropped after a month of notice to their maintainers, were **removed**.
+  - This includes VSCode Server.
+  - This includes Kibana 7 as the ELK stack is unmaintained in nixpkgs and is marked for slow removal.
 
-- GNOME, Pantheon, Cinnamon module no longer forces Qt applications to use Adwaita style since it was buggy and is no longer maintained upstream (specifically, Cinnamon now defaults to the gtk2 style instead, following the default in Linux Mint). If you still want it, you can add the following options to your configuration but it will probably be eventually removed:
+- The application firewall `opensnitch` uses the process monitor method eBPF as
+  default now. This is recommended by upstream. The method may be changed with
+  the setting
+  [services.opensnitch.settings.ProcMonitorMethod](#opt-services.opensnitch.settings.ProcMonitorMethod).
+
+- `paperwork` is updated to v2.2. Documents scanned with this version will not
+  be visible to previous versions if you downgrade. Refer to the [upstream
+  announcement](https://forum.openpaper.work/t/paperwork-2-2-testing-phase/316#important-switch-from-jpeg-to-png-for-new-pages-2)
+  for details and workarounds.
+
+- The latest available version of Nextcloud is v27 (available as
+  `pkgs.nextcloud27`). The installation logic is as follows:
+  - If [`services.nextcloud.package`](#opt-services.nextcloud.package) is
+    specified explicitly, this package will be installed (**recommended**)
+  - If [`system.stateVersion`](#opt-system.stateVersion) is >=23.11,
+    `pkgs.nextcloud27` will be installed by default.
+  - If [`system.stateVersion`](#opt-system.stateVersion) is >=23.05,
+    `pkgs.nextcloud26` will be installed by default.
+  - Please note that an upgrade from v25 (or older) to v27 is not possible
+    directly. Please upgrade to `nextcloud26` (or earlier) first. Nextcloud
+    prohibits skipping major versions while upgrading. You may upgrade by
+    declaring [`services.nextcloud.package =
+    pkgs.nextcloud26;`](options.html#opt-services.nextcloud.package) inbetween.
+
+- `postgresql_11` has been removed since it'll stop receiving fixes on November
+  9th 2023.
+
+- `programs.gnupg.agent.pinentryFlavor` is set in `/etc/gnupg/gpg-agent.conf`
+  now. It will no longer take precedence over a `pinentry-program` set in
+  `~/.gnupg/gpg-agent.conf`.
+
+- `python3.pkgs.flitBuildHook` has been removed. Use `flit-core` and `format =
+  "pyproject"` instead.
+
+- Certificate generation via the `security.acme` limits the concurrent number
+  of running certificate renewals and generation jobs now. This is to avoid
+  spiking resource usage when processing many certificates at once. The limit
+  defaults to *5* and can be adjusted via `maxConcurrentRenewals`. Setting the
+  value to *0* disables the limits altogether.
+
+- `services.borgmatic.settings.location` and
+  `services.borgmatic.configurations.<name>.location` are deprecated, please
+  move your options out of sections to the global scope.
+
+- `services.fail2ban.jails` can be configured with attribute sets now, defining
+  settings and filters instead of lines. The stringed options `daemonConfig`
+  and `extraSettings` have respectively been replaced by `daemonSettings` and
+  `jails.DEFAULT.settings`. Those  use attribute sets.
+
+- The `services.mbpfan` module has the option `aggressive` enabled by default
+  now. This is for better heat moderation. To get the upstream defaults you may
+  disable this.
+
+- Apptainer/Singularity defaults to using `"$out/var/lib"` for the
+  `LOCALSTATEDIR` configuration option instead of the top-level `"/var/lib"`
+  now. This change impacts the `SESSIONDIR` (container-run-time mount point)
+  configuration, which is set to `$LOCALSTATEDIR/<apptainer or
+  singularity>/mnt/session`. This detaches the packages from the top-level
+  directory, rendering the NixOS module optional.
+
+  The default behavior of the NixOS module `programs.singularity` stays
+  unchanged. We add a new option
+  `programs.singularity.enableExternalSysConfDir` (default to `true`) to
+  specify whether to set the top-level `"/var/lib"` as `LOCALSTATEDIR` or not.
+
+- The `services.sslh` module has been updated to follow [RFC
+  0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md).
+  As such, several options have been moved to the freeform attribute set
+  [services.sslh.settings](#opt-services.sslh.settings), which allows to change
+  any of the settings in {manpage}`sslh(8)`.
+
+  In addition, the newly added option
+  [services.sslh.method](#opt-services.sslh.method) allows to switch between
+  the {manpage}`fork(2)`, {manpage}`select(2)` and `libev`-based connection
+  handling method. Refer to the [sslh
+  docs](https://github.com/yrutschle/sslh/blob/master/doc/INSTALL.md#binaries)
+  for a comparison.
+
+- Suricata was upgraded from v6.0 to v7.0 and no longer considers HTTP/2
+  support as experimental. Refer to [upstream release
+  notes](https://forum.suricata.io/t/suricata-7-0-0-released/3715) for more
+  details.
+
+- `teleport` has been upgraded from major version 12 to major version 14.
+  Refer to upstream [upgrade
+  instructions](https://goteleport.com/docs/management/operations/upgrading/)
+  and release notes for
+  [v13](https://goteleport.com/docs/changelog/#1300-050823) and
+  [v14](https://goteleport.com/docs/changelog/#1400-092023). Note that Teleport
+  does not officially support upgrades across more than one major version at a
+  time. If you're running Teleport server components, it is recommended to
+  first upgrade to an intermediate v13.x version by setting
+  `services.teleport.package = pkgs.teleport_13`. Afterwards, this option can
+  be removed to upgrade to the default version (14).
+
+- `zfs` was updated from v2.1.x to v2.2.0, [enabling newer kernel support and
+  adding new features](https://github.com/openzfs/zfs/releases/tag/zfs-2.2.0).
+
+- The use of `sourceRoot = "source";`, `sourceRoot = "source/subdir";`, and
+  similar lines in package derivations using the default `unpackPhase` is
+  deprecated as it requires `unpackPhase` to always produce a directory named
+  "source". Use `sourceRoot = src.name`, `sourceRoot = "${src.name}/subdir";`,
+  or `setSourceRoot = "sourceRoot=$(echo */subdir)";` or similar instead.
+
+- The `django` alias in the python package set was upgraded to Django v4.x.
+  Applications that consume Django should always pin their python environment
+  to a compatible major version, so they can move at their own pace.
 
   ```nix
-  qt = {
-    enable = true;
-    platformTheme = "gnome";
-    style = "adwaita";
+  python = python3.override {
+    packageOverrides = self: super: {
+      django = super.django_3;
+    };
   };
   ```
 
-- `fontconfig` now defaults to using greyscale antialiasing instead of subpixel antialiasing because of a [recommendation from one of the downstreams](https://gitlab.freedesktop.org/fontconfig/fontconfig/-/issues/337). You can change this value by configuring [](#opt-fonts.fontconfig.subpixel.rgba) accordingly.
-
-- The latest available version of Nextcloud is v27 (available as `pkgs.nextcloud27`). The installation logic is as follows:
-  - If [`services.nextcloud.package`](#opt-services.nextcloud.package) is specified explicitly, this package will be installed (**recommended**)
-  - If [`system.stateVersion`](#opt-system.stateVersion) is >=23.11, `pkgs.nextcloud27` will be installed by default.
-  - If [`system.stateVersion`](#opt-system.stateVersion) is >=23.05, `pkgs.nextcloud26` will be installed by default.
-  - Please note that an upgrade from v25 (or older) to v27 directly is not possible. Please upgrade to `nextcloud26` (or earlier) first. Nextcloud prohibits skipping major versions while upgrading. You can upgrade by declaring [`services.nextcloud.package = pkgs.nextcloud26;`](options.html#opt-services.nextcloud.package).
-
-- New options were added to `services.searx` for better SearXNG support, including options for the built-in rate limiter and bot protection and automatically configuring a local redis server.
+- The `qemu-vm.nix` module by default now identifies block devices via
+  persistent names available in `/dev/disk/by-*`. Because the rootDevice is
+  identified by its filesystem label, it needs to be formatted before the VM is
+  started. The functionality of automatically formatting the rootDevice in the
+  initrd is removed from the QEMU module. However, for tests that depend on
+  this functionality, a test utility for the scripted initrd is added
+  (`nixos/tests/common/auto-format-root-device.nix`). To use this in a NixOS
+  test, import the module, e.g. `imports = [
+  ./common/auto-format-root-device.nix ];` When you use the systemd initrd, you
+  can automatically format the root device by setting
+  `virtualisation.fileSystems."/".autoFormat = true;`.
 
-- `jq` was updated to 1.7, its [first release in 5 years](https://github.com/jqlang/jq/releases/tag/jq-1.7).
+- The `electron` packages places its application files in
+  `$out/libexec/electron` instead of `$out/lib/electron` now. Packages using
+  electron-builder will fail to build and need to be adjusted by changing `lib`
+  to `libexec`.
 
-- `zfs` was updated from 2.1.x to 2.2.0, [enabling newer kernel support and adding new features](https://github.com/openzfs/zfs/releases/tag/zfs-2.2.0).
+### New Services {#sec-release-23.11-nixos-new-services}
 
-- The iptables firewall module now installs the `nixos-firewall-tool` which allows the user to easily temporarily open ports through the firewall.
+- [MCHPRS](https://github.com/MCHPR/MCHPRS), a multithreaded Minecraft server
+  built for redstone. Available as
+  [services.mchprs](#opt-services.mchprs.enable).
 
-- Elixir now defaults to version
-  [v1.15](https://elixir-lang.org/blog/2023/06/19/elixir-v1-15-0-released/).
+- [acme-dns](https://github.com/joohoi/acme-dns), a limited DNS server to
+  handle ACME DNS challenges easily and securely. Available as
+  [services.acme-dns](#opt-services.acme-dns.enable).
 
-- A new option was added to the virtualisation module that enables specifying explicitly named network interfaces in QEMU VMs. The existing `virtualisation.vlans` is still supported for cases where the name of the network interface is irrelevant.
+- [frp](https://github.com/fatedier/frp), a fast reverse proxy to help you
+  expose a local server behind a NAT or firewall to the Internet. Available as
+  [services.frp](#opt-services.frp.enable).
 
-- Apptainer/Singularity now defaults to using `"$out/var/lib"` for the `LOCALSTATEDIR` configuration option instead of the top-level `"/var/lib"`. This change impacts the `SESSIONDIR` (container-run-time mount point) configuration, which is set to `$LOCALSTATEDIR/<apptainer or singularity>/mnt/session`. This detaches the packages from the top-level directory, rendering the NixOS module optional.
+- [river](https://github.com/riverwm/river), A dynamic tiling wayland
+  compositor. Available as [programs.river](#opt-programs.river.enable).
 
-  The default behavior of the NixOS module `programs.singularity` stays unchanged. We add a new option `programs.singularity.enableExternalSysConfDir` (default to `true`) to specify whether to set the top-level `"/var/lib"` as `LOCALSTATEDIR` or not.
+- [wayfire](https://wayfire.org), a modular and extensible wayland compositor.
+  Available as [programs.wayfire](#opt-programs.wayfire.enable).
 
-- DocBook option documentation is no longer supported, all module documentation now uses markdown.
+- [mautrix-whatsapp](https://docs.mau.fi/bridges/go/whatsapp/index.html), a
+  Matrix-WhatsApp puppeting bridge. Available as
+  [services.mautrix-whatsapp](#opt-services.mautrix-whatsapp.enable).
 
-- `services.outline` can now be configured to use local filesystem storage instead of S3 storage using [services.outline.storage.storageType](#opt-services.outline.storage.storageType).
+- [hddfancontrol](https://github.com/desbma/hddfancontrol), a service to
+  regulate fan speeds based on hard drive temperature. Available as
+  [services.hddfancontrol](#opt-services.hddfancontrol.enable).
 
-- `paperwork` was updated to version 2.2. Documents scanned with this version will not be visible to previous versions if you downgrade. See the [upstream announcement](https://forum.openpaper.work/t/paperwork-2-2-testing-phase/316#important-switch-from-jpeg-to-png-for-new-pages-2) for details and workarounds.
+- [seatd](https://sr.ht/~kennylevinsen/seatd/), A minimal seat management
+  daemon. Available as [services.seatd](#opt-services.seatd.enable).
 
-- `buildGoModule` `go-modules` attrs have been renamed to `goModules`.
+- [GoToSocial](https://gotosocial.org/), an ActivityPub social network server
+  written in Golang. Available as
+  [services.gotosocial](#opt-services.gotosocial.enable).
 
-- The `fonts.fonts` and `fonts.enableDefaultFonts` options have been renamed to `fonts.packages` and `fonts.enableDefaultPackages` respectively.
+- [Castopod](https://castopod.org/), an open-source hosting platform made for
+  podcasters who want to engage and interact with their audience. Available as
+  [services.castopod](#opt-services.castopod.enable).
 
-- The `services.sslh` module has been updated to follow [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md). As such, several options have been moved to the freeform attribute set [services.sslh.settings](#opt-services.sslh.settings), which allows to change any of the settings in {manpage}`sslh(8)`.
-  In addition, the newly added option [services.sslh.method](#opt-services.sslh.method) allows to switch between the {manpage}`fork(2)`, {manpage}`select(2)` and `libev`-based connection handling method; see the [sslh docs](https://github.com/yrutschle/sslh/blob/master/doc/INSTALL.md#binaries) for a comparison.
+- [Typesense](https://github.com/typesense/typesense), a fast, typo-tolerant
+  search engine for building delightful search experiences. Available as
+  [services.typesense](#opt-services.typesense.enable).
 
-- `pkgs.openvpn3` now optionally supports systemd-resolved. `programs.openvpn3` will automatically enable systemd-resolved support if `config.services.resolved.enable` is enabled.
+* [NS-USBLoader](https://github.com/developersu/ns-usbloader/), an all-in-one
+  tool for managing Nintendo Switch homebrew. Available as
+  [programs.ns-usbloader](#opt-programs.ns-usbloader.enable).
 
-- `services.fail2ban.jails` can now be configured with attribute sets defining settings and filters instead of lines. The stringed options `daemonConfig` and `extraSettings` have respectively been replaced by `daemonSettings` and `jails.DEFAULT.settings` which use attribute sets.
+- [athens](https://github.com/gomods/athens), a Go module datastore and proxy. Available as [services.athens](#opt-services.athens.enable).
 
-- The application firewall `opensnitch` now uses the process monitor method eBPF as default as recommended by upstream. The method can be changed with the setting [services.opensnitch.settings.ProcMonitorMethod](#opt-services.opensnitch.settings.ProcMonitorMethod).
+- [Mobilizon](https://joinmobilizon.org/), a Fediverse platform for publishing
+  events. Available as [services.mobilizon](#opt-services.mobilizon.enable).
 
-- `services.hedgedoc` has been heavily refactored, reducing the amount of declared options in the module. Most of the options should still work without any changes. Some options have been deprecated, as they no longer have any effect. See [#244941](https://github.com/NixOS/nixpkgs/pull/244941) for more details.
+- [Anuko Time Tracker](https://github.com/anuko/timetracker), a simple, easy to
+  use, open source time tracking system. Available as
+  [services.anuko-time-tracker](#opt-services.anuko-time-tracker.enable).
 
-- The [services.woodpecker-server](#opt-services.woodpecker-server.environmentFile) type was changed to list of paths to be more consistent to the woodpecker-agent module
+- [Prometheus MySQL exporter](https://github.com/prometheus/mysqld_exporter), a
+  MySQL server exporter for Prometheus. Available as
+  [services.prometheus.exporters.mysqld](#opt-services.prometheus.exporters.mysqld.enable).
 
-- The module [services.ankisyncd](#opt-services.ankisyncd.package) has been switched to [anki-sync-server-rs](https://github.com/ankicommunity/anki-sync-server-rs) from the old python version, which was difficult to update, had not been updated in a while, and did not support recent versions of anki.
-Unfortunately all servers supporting new clients (newer version of anki-sync-server, anki's built in sync server and this new rust package) do not support the older sync protocol that was used in the old server, so such old clients will also need updating and in particular the anki package in nixpkgs is also being updated in this release.
-The module update takes care of the new config syntax and the data itself (user login and cards) are compatible, so users of the module will be able to just log in again after updating both client and server without any extra action.
+- [LibreNMS](https://www.librenms.org), a auto-discovering PHP/MySQL/SNMP based
+  network monitoring. Available as
+  [services.librenms](#opt-services.librenms.enable).
 
-- `services.matrix-synapse` has new options to configure worker processes for matrix-synapse using [`services.matrix-synapse.workers`](#opt-services.matrix-synapse.workers). It's also now possible to configure a local redis server using [`services.matrix-synapse.configureRedisLocally`](#opt-services.matrix-synapse.configureRedisLocally).
+- [Livebook](https://livebook.dev/), an interactive notebook with support for
+  Elixir, graphs, machine learning, and more. Available as
+  [services.livebook](#opt-services.livebook.enableUserService).
 
-- `services.nginx` gained a `defaultListen` option at server-level with support for PROXY protocol listeners, also `proxyProtocol` is now exposed in `services.nginx.virtualHosts.<name>.listen` option. It is now possible to run PROXY listeners and non-PROXY listeners at a server-level, see [#213510](https://github.com/NixOS/nixpkgs/pull/213510/) for more details.
+- [sitespeed-io](https://sitespeed.io), a tool that can generate metrics such
+  as timings and diagnostics for websites. Available as
+  [services.sitespeed-io](#opt-services.sitespeed-io.enable).
 
-- `services.restic.backups` now adds wrapper scripts to your system path, which set the same environment variables as the service, so restic operations can easily be run from the command line. This behavior can be disabled by setting `createWrapper` to `false`, per backup configuration.
+- [stalwart-mail](https://stalw.art), an all-in-one email server (SMTP, IMAP,
+  JMAP). Available as
+  [services.stalwart-mail](#opt-services.stalwart-mail.enable).
 
-- `services.prometheus.exporters` has a new exporter to monitor electrical power consumption based on PowercapRAPL sensor called [Scaphandre](https://github.com/hubblo-org/scaphandre), see [#239803](https://github.com/NixOS/nixpkgs/pull/239803) for more details.
 
-- The MariaDB C client library was upgraded from 3.2.x to 3.3.x. It is recommended to review the [upstream release notes](https://mariadb.com/kb/en/mariadb-connector-c-33-release-notes/).
+- [tang](https://github.com/latchset/tang), a server for binding data to
+  network presence. Available as [services.tang](#opt-services.tang.enable).
 
-- The module `services.calibre-server` has new options to configure the `host`, `port`, `auth.enable`, `auth.mode` and `auth.userDb` path, see [#216497](https://github.com/NixOS/nixpkgs/pull/216497/) for more details.
+- [Jool](https://nicmx.github.io/Jool/en/index.html), a kernelspace NAT64 and
+  SIIT implementation providing translation between IPv4 and IPv6. Available as
+  [networking.jool.enable](#opt-networking.jool.enable).
 
-- Mattermost has been upgraded to extended support version 8.1 as the previously
-  packaged extended support version 7.8 is [reaching end of life](https://docs.mattermost.com/upgrade/extended-support-release.html).
-  Migration may take some time, see the [changelog](https://docs.mattermost.com/install/self-managed-changelog.html#release-v8-1-extended-support-release)
-  and [important upgrade notes](https://docs.mattermost.com/upgrade/important-upgrade-notes.html).
+- [Home Assistant
+  Satellite](https://github.com/synesthesiam/homeassistant-satellite), a
+  streaming audio satellite for Home Assistant voice pipelines, where you can
+  reuse existing mic and speaker hardware. Available as
+  [services.homeassistant-satellite](#opt-services.homeassistant-satellite.enable).
 
-- `services.prometheus.exporters` has a new [exporter](https://github.com/hipages/php-fpm_exporter) to monitor PHP-FPM processes, see [#240394](https://github.com/NixOS/nixpkgs/pull/240394) for more details.
+- [Apache Guacamole](https://guacamole.apache.org/), a cross-platform,
+  clientless remote desktop gateway. Available as
+  [services.guacamole-server](#opt-services.guacamole-server.enable) and
+  [services.guacamole-client](#opt-services.guacamole-client.enable) services.
 
-- `services.github-runner` / `services.github-runners.<name>` gained the option `nodeRuntimes`. The option defaults to `[ "node20" ]`, i.e., the service supports Node.js 20 GitHub Actions only. The list of Node.js versions accepted by `nodeRuntimes` tracks the versions the upstream GitHub Actions runner supports. See [#249103](https://github.com/NixOS/nixpkgs/pull/249103) for details.
+- [pgBouncer](https://www.pgbouncer.org), a PostgreSQL connection pooler.
+  Available as [services.pgbouncer](#opt-services.pgbouncer.enable).
 
-- `programs.gnupg.agent.pinentryFlavor` is now set in `/etc/gnupg/gpg-agent.conf`, and will no longer take precedence over a `pinentry-program` set in `~/.gnupg/gpg-agent.conf`.
+- [Goss](https://goss.rocks/), a YAML based serverspec alternative tool for
+  validating a server's configuration. Available as
+  [services.goss](#opt-services.goss.enable).
 
-- `programs.gnupg` now has the option `agent.settings` to set verbatim config values in `/etc/gnupg/gpg-agent.conf`.
+- [trust-dns](https://trust-dns.org/), a Rust based DNS server built to be safe
+  and secure from the ground up. Available as
+  [services.trust-dns](#opt-services.trust-dns.enable).
 
-- `dockerTools.buildImage`, `dockerTools.buildLayeredImage` and `dockerTools.streamLayeredImage` now use `lib.makeOverridable` to allow `dockerTools`-based images to be customized more efficiently at the nix-level.
+- [osquery](https://www.osquery.io/), a SQL powered operating system
+  instrumentation, monitoring, and analytics. Available as
+  [services.osquery](#opt-services.osquery.enable).
 
-- `services.influxdb2` now supports doing an automatic initial setup and provisioning of users, organizations, buckets and authentication tokens, see [#249502](https://github.com/NixOS/nixpkgs/pull/249502) for more details.
+- [ebusd](https://ebusd.eu), a daemon for handling communication with eBUS
+  devices connected to a 2-wire bus system ("energy bus" used by numerous
+  heating systems). Available as [services.ebusd](#opt-services.ebusd.enable).
 
-- `wrapHelm` now exposes `passthru.pluginsDir` which can be passed to `helmfile`. For convenience, a top-level package `helmfile-wrapped` has been added, which inherits `passthru.pluginsDir` from `kubernetes-helm-wrapped`. See [#217768](https://github.com/NixOS/nixpkgs/issues/217768) for details.
+- [systemd-sysupdate](https://www.freedesktop.org/software/systemd/man/systemd-sysupdate.html),
+  atomically updates the host OS, container images, portable service images or
+  other sources. Available as [systemd.sysupdate](opt-systemd.sysupdate).
 
-- `boot.initrd.network.udhcp.enable` allows control over dhcp during stage 1 regardless of what `networking.useDHCP` is set to.
+- [eris-server](https://codeberg.org/eris/eris-go), an implementation of the
+  Encoding for Robust Immutable Storage (ERIS). Available as
+  [services.eris-server](#opt-services.eris-server.enable).
 
-- Suricata was upgraded from 6.0 to 7.0 and no longer considers HTTP/2 support as experimental, see [upstream release notes](https://forum.suricata.io/t/suricata-7-0-0-released/3715) for more details.
+- [forgejo](https://forgejo.org/), a git forge and drop-in replacement for
+  Gitea. Available as [services.forgejo](#opt-services.forgejo.enable).
 
-- Cloud support in the `netdata` package is now disabled by default. To enable it use the `netdataCloud` package.
+- `hardware/infiniband.nix` adds infiniband subnet manager support using an
+  [opensm](https://github.com/linux-rdma/opensm) systemd-template service,
+  instantiated on card guids. The module also adds kernel modules and cli
+  tooling to help administrators debug and measure performance. Available as
+  [hardware.infiniband.enable](#opt-hardware.infiniband.enable).
 
-- `networking.nftables` now has the option `networking.nftables.table.<table>` to create tables
-  and have them be updated atomically, instead of flushing the ruleset.
+- [zwave-js](https://github.com/zwave-js/zwave-js-server), a small server
+  wrapper around Z-Wave JS to access it via a WebSocket. Available as
+  [services.zwave-js](#opt-services.zwave-js.enable).
 
-- `networking.nftables` is no longer flushing all rulesets on every reload.
-  Use `networking.nftables.flushRuleset = true;` to get back the old behaviour.
+- [Honk](https://humungus.tedunangst.com/r/honk), a complete ActivityPub server
+  with minimal setup and support costs. Available as
+  [services.honk](#opt-services.honk.enable).
 
-- The `cawbird` package is dropped from nixpkgs, as it got broken by the Twitter API closing down and has been abandoned upstream.
+- [ferretdb](https://www.ferretdb.io/), an open-source proxy, converting the
+  MongoDB 6.0+ wire protocol queries to PostgreSQL or SQLite. Available as
+  [services.ferretdb](options.html#opt-services.ferretdb.enable).
 
-- `hardware.nvidia` gained `datacenter` options for enabling NVIDIA Data Center drivers and configuration of NVLink/NVSwitch topologies through `nv-fabricmanager`.
+- [MicroBin](https://microbin.eu/), a feature rich, performant and secure text
+  and file sharing web application, a "paste bin". Available as
+  [services.microbin](#opt-services.microbin.enable).
 
-- Certificate generation via the `security.acme` now limits the concurrent number of running certificate renewals and generation jobs, to avoid spiking resource usage when processing many certificates at once. The limit defaults to *5* and can be adjusted via `maxConcurrentRenewals`. Setting it to *0* disables the limits altogether.
+- [NNCP](http://www.nncpgo.org/), nncp-daemon and nncp-caller services.
+  Available as [programs.nncp.settings](#opt-programs.nncp.settings) and
+  [services.nncp](#opt-services.nncp.caller.enable).
+
+- [FastNetMon Advanced](https://fastnetmon.com/product-overview/), a commercial
+  high performance DDoS detector and sensor. Available as
+  [services.fastnetmon-advanced](#opt-services.fastnetmon-advanced.enable).
+
+- [tuxedo-rs](https://github.com/AaronErhardt/tuxedo-rs), Rust utilities for
+  interacting with hardware from TUXEDO Computers. Available as
+  [hardware.tuxedo-rs](#opt-hardware.tuxedo-rs.enable).
+
+- [certspotter](https://github.com/SSLMate/certspotter), a certificate
+  transparency log monitor. Available as
+  [services.certspotter](#opt-services.certspotter.enable).
+
+- [audiobookshelf](https://github.com/advplyr/audiobookshelf/), a self-hosted
+  audiobook and podcast server. Available as
+  [services.audiobookshelf](#opt-services.audiobookshelf.enable).
+
+- [ZITADEL](https://zitadel.com), a turnkey identity and access management
+  platform. Available as [services.zitadel](#opt-services.zitadel.enable).
+
+- [exportarr](https://github.com/onedr0p/exportarr), Prometheus Exporters for
+  Bazarr, Lidarr, Prowlarr, Radarr, Readarr, and Sonarr. Available as
+  [services.prometheus.exporters.exportarr-bazarr](#opt-services.prometheus.exporters.exportarr-bazarr.enable)/[services.prometheus.exporters.exportarr-lidarr](#opt-services.prometheus.exporters.exportarr-lidarr.enable)/[services.prometheus.exporters.exportarr-prowlarr](#opt-services.prometheus.exporters.exportarr-prowlarr.enable)/[services.prometheus.exporters.exportarr-radarr](#opt-services.prometheus.exporters.exportarr-radarr.enable)/[services.prometheus.exporters.exportarr-readarr](#opt-services.prometheus.exporters.exportarr-readarr.enable)/[services.prometheus.exporters.exportarr-sonarr](#opt-services.prometheus.exporters.exportarr-sonarr.enable).
+
+- [netclient](https://github.com/gravitl/netclient), an automated WireGuard
+  Management Client. Available as
+  [services.netclient](#opt-services.netclient.enable).
+
+- [trunk-ng](https://github.com/ctron/trunk), A fork of `trunk`: Build, bundle
+  & ship your Rust WASM application to the web
+
+- [virt-manager](https://virt-manager.org/), an UI for managing virtual
+  machines in libvirt. Available as
+  [programs.virt-manager](#opt-programs.virt-manager.enable).
+
+- [Soft Serve](https://github.com/charmbracelet/soft-serve), a tasty,
+  self-hostable Git server for the command line. Available as
+  [services.soft-serve](#opt-services.soft-serve.enable).
+
+- [Rosenpass](https://rosenpass.eu/), a service for post-quantum-secure VPNs
+  with WireGuard. Available as
+  [services.rosenpass](#opt-services.rosenpass.enable).
+
+- [c2FmZQ](https://github.com/c2FmZQ/c2FmZQ/), an application that can securely
+  encrypt, store, and share files, including but not limited to pictures and
+  videos. Available as
+  [services.c2fmzq-server](#opt-services.c2fmzq-server.enable).
+
+- [preload](http://sourceforge.net/projects/preload), a service that makes
+  applications run faster by prefetching binaries and shared objects.
+  Available as [services.preload](#opt-services.preload.enable).
+
+### Other Notable Changes {#sec-release-23.11-nixos-notable-changes}
+
+- The new option `system.switch.enable` was added. It is enabled by default.
+  Disabling it makes the system unable to be reconfigured via `nixos-rebuild`.
+  This is of advantage for image based appliances where updates are handled
+  outside the image.
+
+- `services.searx` receives new options for better SearXNG support. This
+  includes options for the built-in rate limiter, bot protection and
+  automatically configuring a local Redis server.
+
+- The iptables firewall module installs the `nixos-firewall-tool` now which
+  allows the user to easily temporarily open ports through the firewall.
+
+- A new option was added to the virtualisation module that enables specifying
+  explicitly named network interfaces in QEMU VMs. The existing
+  `virtualisation.vlans` is still supported for cases where the name of the
+  network interface is irrelevant.
+
+- `services.outline` can be configured to use local filesystem storage now.
+  Previously ony S3 storage was possible. This may be set using
+  [services.outline.storage.storageType](#opt-services.outline.storage.storageType).
+
+- `pkgs.openvpn3` optionally supports systemd-resolved now. `programs.openvpn3`
+  will automatically enable systemd-resolved support if
+  [services.resolved.enable](#opt-services.resolved.enable) is set to true.
+
+- The
+  [services.woodpecker-server.environmentFile](#opt-services.woodpecker-server.environmentFile)
+  type was changed to list of paths to be more consistent to the
+  woodpecker-agent module
+
+- `services.matrix-synapse` has new options to configure worker processes for
+  matrix-synapse using
+  [`services.matrix-synapse.workers`](#opt-services.matrix-synapse.workers).
+  Configuring a local redis server using
+  [`services.matrix-synapse.configureRedisLocally`](#opt-services.matrix-synapse.configureRedisLocally)
+  is also possible now.
+
+- The `services.nginx` module gained a `defaultListen` option at server-level
+  with support for PROXY protocol listeners. Also `proxyProtocol` is exposed in
+  the `services.nginx.virtualHosts.<name>.listen` option now. This it is
+  possible to run PROXY listeners and non-PROXY listeners at a server-level.
+  Refer to [PR #213510](https://github.com/NixOS/nixpkgs/pull/213510/) for more
+  details.
+
+- `services.restic.backups` adds wrapper scripts to your system path now. This
+  wrapper script sets the same environment variables as the service, so restic
+  operations can easily be run from the command line. This behavior can be
+  disabled by setting `createWrapper` to `false`, for each backup
+  configuration.
+
+- `services.prometheus.exporters` has a new exporter to monitor electrical
+  power consumption based on PowercapRAPL sensor called
+  [Scaphandre](https://github.com/hubblo-org/scaphandre). Refer to [PR
+  #239803](https://github.com/NixOS/nixpkgs/pull/239803) for more details.
+
+- The `services.calibre-server` module has new options to configure the `host`,
+  `port`, `auth.enable`, `auth.mode` and `auth.userDb` path. Refer to [PR
+  #216497](https://github.com/NixOS/nixpkgs/pull/216497/) for more details.
+
+- `services.prometheus.exporters` has a new
+  [exporter](https://github.com/hipages/php-fpm_exporter) to monitor PHP-FPM
+  processes. Refer to [PR
+  #240394](https://github.com/NixOS/nixpkgs/pull/240394) for more details.
+
+- `services.github-runner` and `services.github-runners.<name>` gained the
+  option `nodeRuntimes`. This option defaults to `[ "node20" ]`.  I.e., the
+  service supports Node.js 20 GitHub Actions only. The list of Node.js versions
+  accepted by `nodeRuntimes` tracks the versions the upstream GitHub Actions
+  runner supports. Refer to [PR
+  #249103](https://github.com/NixOS/nixpkgs/pull/249103) for details.
+
+- `programs.gnupg` has the option `agent.settings` now. This allows setting
+  verbatim config values in `/etc/gnupg/gpg-agent.conf`.
+
+- `dockerTools.buildImage`, `dockerTools.buildLayeredImage` and
+  `dockerTools.streamLayeredImage` use `lib.makeOverridable` now . This allows
+  `dockerTools`-based images to be customized more efficiently at the Nix
+  level.
+
+- `services.influxdb2` supports doing an automatic initial setup and
+  provisioning of users, organizations, buckets and authentication tokens now.
+  Refer to [PR #249502](https://github.com/NixOS/nixpkgs/pull/249502) for more
+  details.
+
+- `wrapHelm` exposes `passthru.pluginsDir` now which can be passed to
+  `helmfile`. For convenience, a top-level package `helmfile-wrapped` has been
+  added, which inherits `passthru.pluginsDir` from `kubernetes-helm-wrapped`.
+  Refer to [PR #217768](https://github.com/NixOS/nixpkgs/issues/217768) for
+  more details.
+
+- The `boot.initrd.network.udhcp.enable` option allows control over DHCP during
+  Stage 1 regardless of what `networking.useDHCP` is set to.
+
+- `networking.nftables` has the option `networking.nftables.table.<table>` now. This creates tables
+  and have them be updated atomically, instead of flushing the ruleset.
 
-- New `boot.bcache.enable` (default enabled) allows completely removing `bcache` mount support.
+- `hardware.nvidia` gained `datacenter` options for enabling NVIDIA Data Center
+  drivers and configuration of NVLink/NVSwitch topologies through
+  `nv-fabricmanager`.
 
-- The module `services.mbpfan` now has the option `aggressive` enabled by default for better heat moderation. You can disable it for upstream defaults.
+- The new `boot.bcache.enable` option allows completely removing `bcache`
+  mount support. It is enabled by default.
 
-- `security.sudo` now provides two extra options, that do not change the
+- `security.sudo` provides two extra options now, while not changing the
   module's default behaviour:
   - `defaultOptions` controls the options used for the default rules;
   - `keepTerminfo` controls whether `TERMINFO` and `TERMINFO_DIRS` are preserved
     for `root` and the `wheel` group.
 
-- `virtualisation.googleComputeImage` now provides `efi` option to support UEFI booting.
+- `virtualisation.googleComputeImage` provides a `efi` option to support UEFI
+  booting now.
 
-- CoreDNS can now be built with external plugins by overriding `externalPlugins` and `vendorHash` arguments like this:
+- CoreDNS may be built with external plugins now. This may be done by
+  overriding `externalPlugins` and `vendorHash` arguments like this:
 
   ```
   services.coredns = {
@@ -567,64 +1243,69 @@ The module update takes care of the new config syntax and the data itself (user
   };
   ```
 
-  To get the necessary SRI hash, set `vendorHash = "";`. The build will fail and produce the correct `vendorHash` in the error message.
-
-  If you use this feature, updates to CoreDNS may require updating `vendorHash` by following these steps again.
-
-- `postgresql_11` has been removed since it'll stop receiving fixes on November 9 2023.
-
-- `ffmpeg` default upgraded from `ffmpeg_5` to `ffmpeg_6`.
-
-- `fusuma` now enables the following plugins: [appmatcher](https://github.com/iberianpig/fusuma-plugin-appmatcher), [keypress](https://github.com/iberianpig/fusuma-plugin-keypress), [sendkey](https://github.com/iberianpig/fusuma-plugin-sendkey), [tap](https://github.com/iberianpig/fusuma-plugin-tap) and [wmctrl](https://github.com/iberianpig/fusuma-plugin-wmctrl).
+  To get the necessary SRI hash, set `vendorHash = "";`. The build will fail
+  and produce the correct `vendorHash` in the error message.
 
-- `services.bitcoind` now properly respects the `enable` option.
+  If you use this feature, updates to CoreDNS may require updating `vendorHash`
+  by following these steps again.
 
-- The Home Assistant module now offers support for installing custom components and lovelace modules. Available at [`services.home-assistant.customComponents`](#opt-services.home-assistant.customComponents) and [`services.home-assistant.customLovelaceModules`](#opt-services.home-assistant.customLovelaceModules).
+- Using `fusuma` enables the following plugins now:
+  [appmatcher](https://github.com/iberianpig/fusuma-plugin-appmatcher),
+  [keypress](https://github.com/iberianpig/fusuma-plugin-keypress),
+  [sendkey](https://github.com/iberianpig/fusuma-plugin-sendkey),
+  [tap](https://github.com/iberianpig/fusuma-plugin-tap) and
+  [wmctrl](https://github.com/iberianpig/fusuma-plugin-wmctrl).
 
-- The argument `vendorSha256` of `buildGoModule` is deprecated. Use `vendorHash` instead. ([\#259999](https://github.com/NixOS/nixpkgs/pull/259999))
+- The Home Assistant module offers support for installing custom components and
+  lovelace modules now. Available at
+  [`services.home-assistant.customComponents`](#opt-services.home-assistant.customComponents)
+  and
+  [`services.home-assistant.customLovelaceModules`](#opt-services.home-assistant.customLovelaceModules).
 
-- TeX Live environments can now be built with the new `texlive.withPackages`. The procedure for creating custom TeX packages has been changed, see the [Nixpkgs manual](https://nixos.org/manual/nixpkgs/stable/#sec-language-texlive-custom-packages) for more details.
+- TeX Live environments can now be built with the new `texlive.withPackages`.
+  The procedure for creating custom TeX packages has been changed. Refer to the
+  [Nixpkgs
+  manual](https://nixos.org/manual/nixpkgs/stable/#sec-language-texlive-custom-packages)
+  for more details.
 
-- In `wxGTK32`, the webkit module `wxWebView` has been enabled on all builds; prior releases only enabled this on Darwin.
+- In `wxGTK32`, the webkit module `wxWebView` has been enabled on all builds.
+  Prior releases only enabled this on Darwin.
 
-## Nixpkgs internals {#sec-release-23.11-nixpkgs-internals}
+- Support for WiFi6 (IEEE 802.11ax) and WPA3-SAE-PK was enabled in the
+  `hostapd` package, along with a significant rework of the hostapd module.
 
-- Node.js v14, v16 has been removed as they were end of life. Any dependent packages that contributors were not able to reasonably upgrade were dropped after a month of notice to their maintainers, were **removed**.
-  - This includes VSCode Server.
-  - This includes Kibana 7 as the ELK stack is unmaintained in nixpkgs and is marked for slow removal.
-
-- The use of `sourceRoot = "source";`, `sourceRoot = "source/subdir";`, and similar lines in package derivations using the default `unpackPhase` is deprecated as it requires `unpackPhase` to always produce a directory named "source". Use `sourceRoot = src.name`, `sourceRoot = "${src.name}/subdir";`, or `setSourceRoot = "sourceRoot=$(echo */subdir)";` or similar instead.
+- LXD supports virtual machine instances now to complement the existing
+  container support.
 
-- The `django` alias in the python package set was upgraded to Django 4.x.
-  Applications that consume Django should always pin their python environment
-  to a compatible major version, so they can move at their own pace.
+- The `nixos-rebuild` command has been given a `list-generations` subcommand.
+  Refer to `man nixos-rebuild` for more details.
 
-  ```nix
-  python = python3.override {
-    packageOverrides = self: super: {
-      django = super.django_3;
-    };
-  };
-  ```
+- [`sudo-rs`], a reimplementation of `sudo` in Rust, is now supported.
+  An experimental new module `security.sudo-rs` was added.
+  Switching to it (via ` security.sudo-rs.enable = true;`) introduces
+  slight changes in sudo behaviour, due to `sudo-rs`' current limitations:
+  - terminfo-related environment variables aren't preserved for `root` and `wheel`;
+  - `root` and `wheel` are not given the ability to set (or preserve)
+    arbitrary environment variables.
 
-- The `qemu-vm.nix` module by default now identifies block devices via
-  persistent names available in `/dev/disk/by-*`. Because the rootDevice is
-  identified by its filesystem label, it needs to be formatted before the VM is
-  started. The functionality of automatically formatting the rootDevice in the
-  initrd is removed from the QEMU module. However, for tests that depend on
-  this functionality, a test utility for the scripted initrd is added
-  (`nixos/tests/common/auto-format-root-device.nix`). To use this in a NixOS
-  test, import the module, e.g. `imports = [
-  ./common/auto-format-root-device.nix ];` When you use the systemd initrd, you
-  can automatically format the root device by setting
-  `virtualisation.fileSystems."/".autoFormat = true;`.
+  **Note:** The `sudo-rs` module only takes configuration through `security.sudo-rs`,
+  and in particular does not automatically use previously-set rules; this could be
+  achieved with `security.sudo-rs.extraRules = security.sudo.extraRules;` for instance.
 
-- `python3.pkgs.flitBuildHook` has been removed. Use `flit-core` and `format = "pyproject"` instead.
+[`sudo-rs`]: https://github.com/memorysafety/sudo-rs/
 
--  Now `magma` defaults to `magma-hip` instead of `magma-cuda`. It also
-   respects the `config.cudaSupport` and `config.rocmSupport` options.
+- There is a new NixOS option when writing NixOS tests
+  `testing.initrdBackdoor`, that enables `backdoor.service` in initrd. Requires
+  `boot.initrd.systemd.enable` to be enabled. Boot will pause in Stage 1 at
+  `initrd.target`, and will listen for commands from the `Machine` python
+  interface, just like Stage 2 normally does. This enables commands to be sent
+  to test and debug Stage 1. Use `machine.switch_root()` to leave Stage 1 and
+  proceed to Stage 2.
 
-- The `extend` function of `llvmPackages` has been removed due it coming from the `tools` attrset thus only extending the `tool` attrset. A possible replacement is to construct the set from `libraries` and `tools`, or patch nixpkgs.
+- The Linux kernel module `msr` (refer to
+  [`msr(4)`](https://man7.org/linux/man-pages/man4/msr.4.html)), which provides
+  an interface to read and write the model-specific registers (MSRs) of an x86
+  CPU, can now be configured via `hardware.cpu.x86.msr`.
 
 - The `qemu-vm.nix` module now supports disabling overriding `fileSystems` with
   `virtualisation.fileSystems`. This enables the user to boot VMs from
@@ -632,63 +1313,64 @@ The module update takes care of the new config syntax and the data itself (user
   qemu-vm module from overriding `fileSystems` by setting
   `virtualisation.fileSystems = lib.mkForce { };`.
 
-- The `electron` packages now places its application files in `$out/libexec/electron` instead of `$out/lib/electron`. Packages using electron-builder will fail to build and need to be adjusted by changing `lib` to `libexec`.
-
-- `teleport` has been upgraded from major version 12 to major version 14. Please see upstream [upgrade instructions](https://goteleport.com/docs/management/operations/upgrading/) and release notes for versions [13](https://goteleport.com/docs/changelog/#1300-050823) and [14](https://goteleport.com/docs/changelog/#1400-092023). Note that Teleport does not officially support upgrades across more than one major version at a time. If you're running Teleport server components, it is recommended to first upgrade to an intermediate 13.x version by setting `services.teleport.package = pkgs.teleport_13`. Afterwards, this option can be removed to upgrade to the default version (14).
+## Nixpkgs Library {#sec-release-23.11-nixpkgs-lib}
 
-- The Linux kernel module `msr` (see [`msr(4)`](https://man7.org/linux/man-pages/man4/msr.4.html)), which provides an interface to read and write the model-specific registers (MSRs) of an x86 CPU, can now be configured via `hardware.cpu.x86.msr`.
-
-- Docker now defaults to 24, as 20.10 is stopping to receive security updates and bug fixes after [December 10, 2023](https://github.com/moby/moby/discussions/45104).
-
-- There is a new NixOS option when writing NixOS tests `testing.initrdBackdoor`, that enables `backdoor.service` in initrd. Requires `boot.initrd.systemd.enable` to be enabled. Boot will pause in stage 1 at `initrd.target`, and will listen for commands from the `Machine` python interface, just like stage 2 normally does. This enables commands to be sent to test and debug stage 1. Use `machine.switch_root()` to leave stage 1 and proceed to stage 2.
-
-## Nixpkgs library changes {#sec-release-23.11-lib}
-
-### Breaking changes {#sec-release-23.11-lib-breaking}
+### Breaking Changes {#sec-release-23.11-lib-breaking}
 
 - [`lib.lists.foldl'`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.foldl-prime)
-  now always evaluates the initial accumulator argument first.
-  If you depend on the lazier behavior, consider using [`lib.lists.foldl`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.foldl)
-  or [`builtins.foldl'`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-foldl') instead.
+  now always evaluates the initial accumulator argument first. If you depend on
+  the lazier behavior, consider using
+  [`lib.lists.foldl`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.foldl)
+  or
+  [`builtins.foldl'`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-foldl')
+  instead.
 - [`lib.attrsets.foldlAttrs`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.attrsets.foldlAttrs)
   now always evaluates the initial accumulator argument first.
 - Now that the internal NixOS transition to Markdown documentation is complete,
   `lib.options.literalDocBook` has been removed after deprecation in 22.11.
 - `lib.types.string` is now fully deprecated and gives a warning when used.
 
-### Additions and improvements {#sec-release-23.11-lib-additions-improvements}
+### Additions and Improvements {#sec-release-23.11-lib-additions-improvements}
 
 - [`lib.fileset`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-fileset):
-  A new sub-library to select local files to use for sources,
-  designed to be easy and safe to use.
+  A new sub-library to select local files to use for sources, designed to be
+  easy and safe to use.
 
-  This aims to be a replacement for `lib.sources`-based filtering.
-  To learn more about it, see [the blog post](https://www.tweag.io/blog/2023-11-28-file-sets/)
-  or [the tutorial](https://nix.dev/tutorials/file-sets).
+  This aims to be a replacement for `lib.sources`-based filtering. To learn
+  more about it, see [the blog
+  post](https://www.tweag.io/blog/2023-11-28-file-sets/) or [the
+  tutorial](https://nix.dev/tutorials/file-sets).
 
 - [`lib.gvariant`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-gvariant):
-  A partial and basic implementation of GVariant formatted strings.
-  See [GVariant Format Strings](https://docs.gtk.org/glib/gvariant-format-strings.html) for details.
+  A partial and basic implementation of GVariant formatted strings. See
+  [GVariant Format
+  Strings](https://docs.gtk.org/glib/gvariant-format-strings.html) for details.
 
   :::{.warning}
   This API is not considered fully stable and it might therefore
   change in backwards incompatible ways without prior notice.
   :::
 
-- [`lib.asserts`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-asserts): New function:
+- [`lib.asserts`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-asserts):
+  New function:
   [`assertEachOneOf`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.asserts.assertEachOneOf).
-- [`lib.attrsets`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-attrsets): New function:
+- [`lib.attrsets`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-attrsets):
+  New function:
   [`attrsToList`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.attrsets.attrsToList).
-- [`lib.customisation`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-customisation): New function:
+- [`lib.customisation`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-customisation):
+  New function:
   [`makeScopeWithSplicing'`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.customisation.makeScopeWithSplicing-prime).
-- [`lib.fixedPoints`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-fixedPoints): Documentation improvements for
+- [`lib.fixedPoints`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-fixedPoints):
+  Documentation improvements for
   [`lib.fixedPoints.fix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.fixedPoints.fix).
 - `lib.generators`: New functions:
   [`mkDconfKeyValue`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.generators.mkDconfKeyValue),
   [`toDconfINI`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.generators.toDconfINI).
 
-  `lib.generators.toKeyValue` now supports the `indent` attribute in its first argument.
-- [`lib.lists`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-lists): New functions:
+  `lib.generators.toKeyValue` now supports the `indent` attribute in its first
+  argument.
+- [`lib.lists`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-lists):
+  New functions:
   [`findFirstIndex`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.findFirstIndex),
   [`hasPrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.hasPrefix),
   [`removePrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.removePrefix),
@@ -697,33 +1379,37 @@ The module update takes care of the new config syntax and the data itself (user
 
   Documentation improvements for
   [`lib.lists.foldl'`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.foldl-prime).
-- [`lib.meta`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-meta): Documentation of functions now gets rendered
-- [`lib.path`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-path): New functions:
+- [`lib.meta`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-meta):
+  Documentation of functions now gets rendered
+- [`lib.path`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-path):
+  New functions:
   [`hasPrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.path.hasPrefix),
   [`removePrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.path.removePrefix),
   [`splitRoot`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.path.splitRoot),
   [`subpath.components`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.path.subpath.components).
-- [`lib.strings`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-strings): New functions:
+- [`lib.strings`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-strings):
+  New functions:
   [`replicate`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.strings.replicate),
   [`cmakeOptionType`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.strings.cmakeOptionType),
   [`cmakeBool`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.strings.cmakeBool),
   [`cmakeFeature`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.strings.cmakeFeature).
-- [`lib.trivial`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-trivial): New function:
+- [`lib.trivial`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-trivial):
+  New function:
   [`mirrorFunctionArgs`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.trivial.mirrorFunctionArgs).
 - `lib.systems`: New function:
   [`equals`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.systems.equals).
-- [`lib.options`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-options): Improved documentation for
+- [`lib.options`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-options):
+  Improved documentation for
   [`mkPackageOption`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.options.mkPackageOption).
 
   [`mkPackageOption`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.options.mkPackageOption).
   now also supports the `pkgsText` attribute.
 
 Module system:
-- Options in the `options` module argument now have the `declarationPositions` attribute
-  containing the position where the option was declared:
+- Options in the `options` module argument now have the `declarationPositions`
+  attribute containing the position where the option was declared:
   ```
-  $ nix repl -f '<nixpkgs/nixos>'
-  [...]
+  $ nix-repl -f '<nixpkgs/nixos>' [...]
   nix-repl> :p options.environment.systemPackages.declarationPositions
   [ {
     column = 7;
@@ -731,12 +1417,14 @@ Module system:
     line = 62;
   } ]
   ```
+
   Not to be confused with `definitionsWithLocations`, which is the same but for option _definitions_.
 - Improved error message for option declarations missing `mkOption`
 
 ### Deprecations {#sec-release-23.11-lib-deprecations}
 
-- `lib.meta.getExe pkg` (also available as `lib.getExe`) now gives a warning if `pkg.meta.mainProgram` is not set,
-  but it continues to default to the derivation name.
-  Nixpkgs accepts PRs that set `meta.mainProgram` on packages where it makes sense.
-  Use `lib.getExe' pkg "some-command"` to avoid the warning and/or select a different executable.
+- `lib.meta.getExe pkg` (also available as `lib.getExe`) now gives a warning if
+  `pkg.meta.mainProgram` is not set, but it continues to default to the
+  derivation name. Nixpkgs accepts PRs that set `meta.mainProgram` on packages
+  where it makes sense. Use `lib.getExe' pkg "some-command"` to avoid the
+  warning and/or select a different executable.
diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md
index d96992b018ab..b6b343145d78 100644
--- a/nixos/doc/manual/release-notes/rl-2405.section.md
+++ b/nixos/doc/manual/release-notes/rl-2405.section.md
@@ -20,7 +20,8 @@ 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. -->
 
-- Create the first release note entry in this section!
+- `mkosi` was updated to v19. Parts of the user interface have changed. Consult the
+  [release notes](https://github.com/systemd/mkosi/releases/tag/v19) for a list of changes.
 
 ## Other Notable Changes {#sec-release-24.05-notable-changes}
 
diff --git a/nixos/modules/hardware/ckb-next.nix b/nixos/modules/hardware/ckb-next.nix
index 79977939eec8..34f951a7446f 100644
--- a/nixos/modules/hardware/ckb-next.nix
+++ b/nixos/modules/hardware/ckb-next.nix
@@ -24,14 +24,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.ckb-next;
-        defaultText = literalExpression "pkgs.ckb-next";
-        description = lib.mdDoc ''
-          The package implementing the Corsair keyboard/mouse driver.
-        '';
-      };
+      package = mkPackageOption pkgs "ckb-next" { };
     };
 
     config = mkIf cfg.enable {
diff --git a/nixos/modules/hardware/digitalbitbox.nix b/nixos/modules/hardware/digitalbitbox.nix
index 74e46bd34ace..ea04d72a63a5 100644
--- a/nixos/modules/hardware/digitalbitbox.nix
+++ b/nixos/modules/hardware/digitalbitbox.nix
@@ -16,11 +16,10 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.digitalbitbox;
-      defaultText = literalExpression "pkgs.digitalbitbox";
-      description = lib.mdDoc "The Digital Bitbox package to use. This can be used to install a package with udev rules that differ from the defaults.";
+    package = mkPackageOption pkgs "digitalbitbox" {
+      extraDescription = ''
+        This can be used to install a package with udev rules that differ from the defaults.
+      '';
     };
   };
 
diff --git a/nixos/modules/hardware/opentabletdriver.nix b/nixos/modules/hardware/opentabletdriver.nix
index e3f418abce4f..f103da14c9dd 100644
--- a/nixos/modules/hardware/opentabletdriver.nix
+++ b/nixos/modules/hardware/opentabletdriver.nix
@@ -26,14 +26,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.opentabletdriver;
-        defaultText = literalExpression "pkgs.opentabletdriver";
-        description = lib.mdDoc ''
-          OpenTabletDriver derivation to use.
-        '';
-      };
+      package = mkPackageOption pkgs "opentabletdriver" { };
 
       daemon = {
         enable = mkOption {
diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix
index 3c76d17086b5..0dd4bf3f16f3 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -26,14 +26,8 @@ in
       '';
     };
 
-    package = mkOption {
-      type = package;
-      default = pkgs.findutils.locate;
-      defaultText = literalExpression "pkgs.findutils.locate";
-      example = literalExpression "pkgs.mlocate";
-      description = lib.mdDoc ''
-        The locate implementation to use
-      '';
+    package = mkPackageOption pkgs [ "findutils" "locate" ] {
+      example = "mlocate";
     };
 
     interval = mkOption {
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index b92786506a29..e40b7ed8015f 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -480,6 +480,7 @@
   ./services/desktops/telepathy.nix
   ./services/desktops/tumbler.nix
   ./services/desktops/zeitgeist.nix
+  ./services/development/athens.nix
   ./services/development/blackfire.nix
   ./services/development/bloop.nix
   ./services/development/distccd.nix
@@ -1441,6 +1442,7 @@
   ./system/boot/stratisroot.nix
   ./system/boot/modprobe.nix
   ./system/boot/networkd.nix
+  ./system/boot/unl0kr.nix
   ./system/boot/plymouth.nix
   ./system/boot/resolved.nix
   ./system/boot/shutdown.nix
@@ -1538,9 +1540,10 @@
   ./virtualisation/waydroid.nix
   ./virtualisation/xe-guest-utilities.nix
   ./virtualisation/xen-dom0.nix
-  { documentation.nixos.extraModules = [
-    ./virtualisation/qemu-vm.nix
-    ./image/repart.nix
+  {
+    documentation.nixos.extraModules = [
+      ./virtualisation/qemu-vm.nix
+      ./image/repart.nix
     ];
   }
 ]
diff --git a/nixos/modules/programs/atop.nix b/nixos/modules/programs/atop.nix
index a5f4d990bdbe..7d9491d1fc1f 100644
--- a/nixos/modules/programs/atop.nix
+++ b/nixos/modules/programs/atop.nix
@@ -16,14 +16,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "Atop");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.atop;
-        defaultText = literalExpression "pkgs.atop";
-        description = lib.mdDoc ''
-          Which package to use for Atop.
-        '';
-      };
+      package = mkPackageOption pkgs "atop" { };
 
       netatop = {
         enable = mkOption {
diff --git a/nixos/modules/programs/captive-browser.nix b/nixos/modules/programs/captive-browser.nix
index 032c0e71f1f4..1c3ee7638ee0 100644
--- a/nixos/modules/programs/captive-browser.nix
+++ b/nixos/modules/programs/captive-browser.nix
@@ -5,7 +5,8 @@ let
 
   inherit (lib)
     concatStringsSep escapeShellArgs optionalString
-    literalExpression mkEnableOption mkIf mkOption mkOptionDefault types;
+    literalExpression mkEnableOption mkPackageOption mkIf mkOption
+    mkOptionDefault types;
 
   requiresSetcapWrapper = config.boot.kernelPackages.kernelOlder "5.7" && cfg.bindInterface;
 
@@ -50,12 +51,7 @@ in
     programs.captive-browser = {
       enable = mkEnableOption (lib.mdDoc "captive browser");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.captive-browser;
-        defaultText = literalExpression "pkgs.captive-browser";
-        description = lib.mdDoc "Which package to use for captive-browser";
-      };
+      package = mkPackageOption pkgs "captive-browser" { };
 
       interface = mkOption {
         type = types.str;
diff --git a/nixos/modules/programs/digitalbitbox/default.nix b/nixos/modules/programs/digitalbitbox/default.nix
index 5ee6cdafe63a..bdacbc010c41 100644
--- a/nixos/modules/programs/digitalbitbox/default.nix
+++ b/nixos/modules/programs/digitalbitbox/default.nix
@@ -16,11 +16,10 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.digitalbitbox;
-      defaultText = literalExpression "pkgs.digitalbitbox";
-      description = lib.mdDoc "The Digital Bitbox package to use. This can be used to install a package with udev rules that differ from the defaults.";
+    package = mkPackageOption pkgs "digitalbitbox" {
+      extraDescription = ''
+        This can be used to install a package with udev rules that differ from the defaults.
+      '';
     };
   };
 
diff --git a/nixos/modules/programs/dmrconfig.nix b/nixos/modules/programs/dmrconfig.nix
index 20a0dc9556da..29268cdfeb50 100644
--- a/nixos/modules/programs/dmrconfig.nix
+++ b/nixos/modules/programs/dmrconfig.nix
@@ -21,12 +21,7 @@ in {
         relatedPackages = [ "dmrconfig" ];
       };
 
-      package = mkOption {
-        default = pkgs.dmrconfig;
-        type = types.package;
-        defaultText = literalExpression "pkgs.dmrconfig";
-        description = lib.mdDoc "dmrconfig derivation to use";
-      };
+      package = mkPackageOption pkgs "dmrconfig" { };
     };
   };
 
diff --git a/nixos/modules/programs/evince.nix b/nixos/modules/programs/evince.nix
index 9ed5ea0feb04..ed543d35cc5e 100644
--- a/nixos/modules/programs/evince.nix
+++ b/nixos/modules/programs/evince.nix
@@ -24,12 +24,7 @@ in {
       enable = mkEnableOption
         (lib.mdDoc "Evince, the GNOME document viewer");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.evince;
-        defaultText = literalExpression "pkgs.evince";
-        description = lib.mdDoc "Evince derivation to use.";
-      };
+      package = mkPackageOption pkgs "evince" { };
 
     };
 
diff --git a/nixos/modules/programs/feedbackd.nix b/nixos/modules/programs/feedbackd.nix
index e3fde947a3df..010287e5cd56 100644
--- a/nixos/modules/programs/feedbackd.nix
+++ b/nixos/modules/programs/feedbackd.nix
@@ -12,14 +12,7 @@ in {
 
         Your user needs to be in the `feedbackd` group to trigger effects
       '');
-      package = mkOption {
-        description = lib.mdDoc ''
-          Which feedbackd package to use.
-        '';
-        type = types.package;
-        default = pkgs.feedbackd;
-        defaultText = literalExpression "pkgs.feedbackd";
-      };
+      package = mkPackageOption pkgs "feedbackd" { };
     };
   };
   config = mkIf cfg.enable {
diff --git a/nixos/modules/programs/file-roller.nix b/nixos/modules/programs/file-roller.nix
index ca0c4d1b2a2a..a343d4a261c9 100644
--- a/nixos/modules/programs/file-roller.nix
+++ b/nixos/modules/programs/file-roller.nix
@@ -23,12 +23,7 @@ in {
 
       enable = mkEnableOption (lib.mdDoc "File Roller, an archive manager for GNOME");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.gnome.file-roller;
-        defaultText = literalExpression "pkgs.gnome.file-roller";
-        description = lib.mdDoc "File Roller derivation to use.";
-      };
+      package = mkPackageOption pkgs [ "gnome" "file-roller" ] { };
 
     };
 
diff --git a/nixos/modules/programs/flexoptix-app.nix b/nixos/modules/programs/flexoptix-app.nix
index 2524e7ba4d58..6f37fe54667c 100644
--- a/nixos/modules/programs/flexoptix-app.nix
+++ b/nixos/modules/programs/flexoptix-app.nix
@@ -9,12 +9,7 @@ in {
     programs.flexoptix-app = {
       enable = mkEnableOption (lib.mdDoc "FLEXOPTIX app + udev rules");
 
-      package = mkOption {
-        description = lib.mdDoc "FLEXOPTIX app package to use";
-        type = types.package;
-        default = pkgs.flexoptix-app;
-        defaultText = literalExpression "pkgs.flexoptix-app";
-      };
+      package = mkPackageOption pkgs "flexoptix-app" { };
     };
   };
 
diff --git a/nixos/modules/programs/gamescope.nix b/nixos/modules/programs/gamescope.nix
index a31295e736df..594e5be5fd58 100644
--- a/nixos/modules/programs/gamescope.nix
+++ b/nixos/modules/programs/gamescope.nix
@@ -23,14 +23,7 @@ in
   options.programs.gamescope = {
     enable = mkEnableOption (mdDoc "gamescope");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.gamescope;
-      defaultText = literalExpression "pkgs.gamescope";
-      description = mdDoc ''
-        The GameScope package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "gamescope" { };
 
     capSysNice = mkOption {
       type = types.bool;
diff --git a/nixos/modules/programs/git.nix b/nixos/modules/programs/git.nix
index 710dee349d59..8fb69cbae28f 100644
--- a/nixos/modules/programs/git.nix
+++ b/nixos/modules/programs/git.nix
@@ -11,12 +11,8 @@ in
     programs.git = {
       enable = mkEnableOption (lib.mdDoc "git");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.git;
-        defaultText = literalExpression "pkgs.git";
-        example = literalExpression "pkgs.gitFull";
-        description = lib.mdDoc "The git package to use";
+      package = mkPackageOption pkgs "git" {
+        example = "gitFull";
       };
 
       config = mkOption {
@@ -65,12 +61,7 @@ in
       lfs = {
         enable = mkEnableOption (lib.mdDoc "git-lfs");
 
-        package = mkOption {
-          type = types.package;
-          default = pkgs.git-lfs;
-          defaultText = literalExpression "pkgs.git-lfs";
-          description = lib.mdDoc "The git-lfs package to use";
-        };
+        package = mkPackageOption pkgs "git-lfs" { };
       };
     };
   };
diff --git a/nixos/modules/programs/gnupg.nix b/nixos/modules/programs/gnupg.nix
index aa1a536247ce..8f82de033666 100644
--- a/nixos/modules/programs/gnupg.nix
+++ b/nixos/modules/programs/gnupg.nix
@@ -29,14 +29,7 @@ in
 {
 
   options.programs.gnupg = {
-    package = mkOption {
-      type = types.package;
-      default = pkgs.gnupg;
-      defaultText = literalExpression "pkgs.gnupg";
-      description = lib.mdDoc ''
-        The gpg package that should be used.
-      '';
-    };
+    package = mkPackageOption pkgs "gnupg" { };
 
     agent.enable = mkOption {
       type = types.bool;
diff --git a/nixos/modules/programs/htop.nix b/nixos/modules/programs/htop.nix
index 777ea709836e..9dbab954b2bb 100644
--- a/nixos/modules/programs/htop.nix
+++ b/nixos/modules/programs/htop.nix
@@ -18,14 +18,7 @@ in
 {
 
   options.programs.htop = {
-    package = mkOption {
-      type = types.package;
-      default = pkgs.htop;
-      defaultText = lib.literalExpression "pkgs.htop";
-      description = lib.mdDoc ''
-        The htop package that should be used.
-      '';
-    };
+    package = mkPackageOption pkgs "htop" { };
 
     enable = mkEnableOption (lib.mdDoc "htop process monitor");
 
diff --git a/nixos/modules/programs/i3lock.nix b/nixos/modules/programs/i3lock.nix
index 466ae59c9277..44e2e04c2799 100644
--- a/nixos/modules/programs/i3lock.nix
+++ b/nixos/modules/programs/i3lock.nix
@@ -13,16 +13,12 @@ in {
   options = {
     programs.i3lock = {
       enable = mkEnableOption (mdDoc "i3lock");
-      package = mkOption {
-        type        = types.package;
-        default     = pkgs.i3lock;
-        defaultText = literalExpression "pkgs.i3lock";
-        example     = literalExpression ''
-          pkgs.i3lock-color
-        '';
-        description = mdDoc ''
-          Specify which package to use for the i3lock program,
+      package = mkPackageOption pkgs "i3lock" {
+        example = "i3lock-color";
+        extraDescription = ''
+          ::: {.note}
           The i3lock package must include a i3lock file or link in its out directory in order for the u2fSupport option to work correctly.
+          :::
         '';
       };
       u2fSupport = mkOption {
diff --git a/nixos/modules/programs/java.nix b/nixos/modules/programs/java.nix
index c5f83858d06a..251192183ebf 100644
--- a/nixos/modules/programs/java.nix
+++ b/nixos/modules/programs/java.nix
@@ -30,13 +30,8 @@ in
         '';
       };
 
-      package = mkOption {
-        default = pkgs.jdk;
-        defaultText = literalExpression "pkgs.jdk";
-        description = lib.mdDoc ''
-          Java package to install. Typical values are pkgs.jdk or pkgs.jre.
-        '';
-        type = types.package;
+      package = mkPackageOption pkgs "jdk" {
+        example = "jre";
       };
 
       binfmt = mkEnableOption (lib.mdDoc "binfmt to execute java jar's and classes");
diff --git a/nixos/modules/programs/k40-whisperer.nix b/nixos/modules/programs/k40-whisperer.nix
index 27a79caa4b53..96cf159f2cf7 100644
--- a/nixos/modules/programs/k40-whisperer.nix
+++ b/nixos/modules/programs/k40-whisperer.nix
@@ -20,15 +20,7 @@ in
       default = "k40";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.k40-whisperer;
-      defaultText = literalExpression "pkgs.k40-whisperer";
-      example = literalExpression "pkgs.k40-whisperer";
-      description = lib.mdDoc ''
-        K40 Whisperer package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "k40-whisperer" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/programs/kdeconnect.nix b/nixos/modules/programs/kdeconnect.nix
index 4ba156f2db8d..a16fad03eefe 100644
--- a/nixos/modules/programs/kdeconnect.nix
+++ b/nixos/modules/programs/kdeconnect.nix
@@ -11,14 +11,8 @@ with lib;
       `gnomeExtensions.gsconnect` as an alternative
       implementation if you use Gnome
     '');
-    package = mkOption {
-      default = pkgs.plasma5Packages.kdeconnect-kde;
-      defaultText = literalExpression "pkgs.plasma5Packages.kdeconnect-kde";
-      type = types.package;
-      example = literalExpression "pkgs.gnomeExtensions.gsconnect";
-      description = lib.mdDoc ''
-        The package providing the implementation for kdeconnect.
-      '';
+    package = mkPackageOption pkgs [ "plasma5Packages" "kdeconnect-kde" ] {
+      example = "gnomeExtensions.gsconnect";
     };
   };
   config =
diff --git a/nixos/modules/programs/mininet.nix b/nixos/modules/programs/mininet.nix
index 02272729d233..01ffd811e70e 100644
--- a/nixos/modules/programs/mininet.nix
+++ b/nixos/modules/programs/mininet.nix
@@ -5,26 +5,39 @@
 with lib;
 
 let
-  cfg  = config.programs.mininet;
+  cfg = config.programs.mininet;
 
-  generatedPath = with pkgs; makeSearchPath "bin"  [
-    iperf ethtool iproute2 socat
+  telnet = pkgs.runCommand "inetutils-telnet"
+    { }
+    ''
+      mkdir -p $out/bin
+      ln -s ${pkgs.inetutils}/bin/telnet $out/bin
+    '';
+
+  generatedPath = with pkgs; makeSearchPath "bin" [
+    iperf
+    ethtool
+    iproute2
+    socat
+    # mn errors out without a telnet binary
+    # pkgs.inetutils brings an undesired ifconfig into PATH see #43105
+    nettools
+    telnet
   ];
 
-  pyEnv = pkgs.python.withPackages(ps: [ ps.mininet-python ]);
+  pyEnv = pkgs.python3.withPackages (ps: [ ps.mininet-python ]);
 
   mnexecWrapped = pkgs.runCommand "mnexec-wrapper"
-    { nativeBuildInputs = [ pkgs.makeWrapper pkgs.pythonPackages.wrapPython ]; }
+    { nativeBuildInputs = [ pkgs.makeWrapper pkgs.python3Packages.wrapPython ]; }
     ''
       makeWrapper ${pkgs.mininet}/bin/mnexec \
         $out/bin/mnexec \
         --prefix PATH : "${generatedPath}"
 
-      ln -s ${pyEnv}/bin/mn $out/bin/mn
-
-      # mn errors out without a telnet binary
-      # pkgs.inetutils brings an undesired ifconfig into PATH see #43105
-      ln -s ${pkgs.inetutils}/bin/telnet $out/bin/telnet
+      makeWrapper ${pyEnv}/bin/mn \
+        $out/bin/mn \
+        --prefix PYTHONPATH : "${pyEnv}/${pyEnv.sitePackages}" \
+        --prefix PATH : "${generatedPath}"
     '';
 in
 {
diff --git a/nixos/modules/programs/mtr.nix b/nixos/modules/programs/mtr.nix
index 173f24729417..e247d645b861 100644
--- a/nixos/modules/programs/mtr.nix
+++ b/nixos/modules/programs/mtr.nix
@@ -17,14 +17,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.mtr;
-        defaultText = literalExpression "pkgs.mtr";
-        description = lib.mdDoc ''
-          The package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "mtr" { };
     };
   };
 
diff --git a/nixos/modules/programs/neovim.nix b/nixos/modules/programs/neovim.nix
index 1b53b9b5d919..77abec7ef7e9 100644
--- a/nixos/modules/programs/neovim.nix
+++ b/nixos/modules/programs/neovim.nix
@@ -86,12 +86,7 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.neovim-unwrapped;
-      defaultText = literalExpression "pkgs.neovim-unwrapped";
-      description = lib.mdDoc "The package to use for the neovim binary.";
-    };
+    package = mkPackageOption pkgs "neovim-unwrapped" { };
 
     finalPackage = mkOption {
       type = types.package;
diff --git a/nixos/modules/programs/nix-index.nix b/nixos/modules/programs/nix-index.nix
index a494b9d8c2c9..f3e7d22737fa 100644
--- a/nixos/modules/programs/nix-index.nix
+++ b/nixos/modules/programs/nix-index.nix
@@ -5,12 +5,7 @@ in {
   options.programs.nix-index = with lib; {
     enable = mkEnableOption (lib.mdDoc "nix-index, a file database for nixpkgs");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.nix-index;
-      defaultText = literalExpression "pkgs.nix-index";
-      description = lib.mdDoc "Package providing the `nix-index` tool.";
-    };
+    package = mkPackageOption pkgs "nix-index" { };
 
     enableBashIntegration = mkEnableOption (lib.mdDoc "Bash integration") // {
       default = true;
diff --git a/nixos/modules/programs/nncp.nix b/nixos/modules/programs/nncp.nix
index 98fea84ab740..e078b718410c 100644
--- a/nixos/modules/programs/nncp.nix
+++ b/nixos/modules/programs/nncp.nix
@@ -23,12 +23,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.nncp;
-      defaultText = literalExpression "pkgs.nncp";
-      description = lib.mdDoc "The NNCP package to use system-wide.";
-    };
+    package = mkPackageOption pkgs "nncp" { };
 
     secrets = mkOption {
       type = with types; listOf str;
diff --git a/nixos/modules/programs/noisetorch.nix b/nixos/modules/programs/noisetorch.nix
index c022b01d79af..d8135877d02f 100644
--- a/nixos/modules/programs/noisetorch.nix
+++ b/nixos/modules/programs/noisetorch.nix
@@ -8,14 +8,7 @@ in
   options.programs.noisetorch = {
     enable = mkEnableOption (lib.mdDoc "noisetorch + setcap wrapper");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.noisetorch;
-      defaultText = literalExpression "pkgs.noisetorch";
-      description = lib.mdDoc ''
-        The noisetorch package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "noisetorch" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/programs/npm.nix b/nixos/modules/programs/npm.nix
index c41fea326149..8113ea1ba4ea 100644
--- a/nixos/modules/programs/npm.nix
+++ b/nixos/modules/programs/npm.nix
@@ -13,12 +13,8 @@ in
     programs.npm = {
       enable = mkEnableOption (lib.mdDoc "{command}`npm` global config");
 
-      package = mkOption {
-        type = types.package;
-        description = lib.mdDoc "The npm package version / flavor to use";
-        default = pkgs.nodePackages.npm;
-        defaultText = literalExpression "pkgs.nodePackages.npm";
-        example = literalExpression "pkgs.nodePackages_13_x.npm";
+      package = mkPackageOption pkgs [ "nodePackages" "npm" ] {
+        example = "nodePackages_13_x.npm";
       };
 
       npmrc = mkOption {
diff --git a/nixos/modules/programs/proxychains.nix b/nixos/modules/programs/proxychains.nix
index 9bdd5d405668..acd41f355244 100644
--- a/nixos/modules/programs/proxychains.nix
+++ b/nixos/modules/programs/proxychains.nix
@@ -51,8 +51,8 @@ in {
 
       enable = mkEnableOption (lib.mdDoc "installing proxychains configuration");
 
-      package = mkPackageOptionMD pkgs "proxychains" {
-        example = "pkgs.proxychains-ng";
+      package = mkPackageOption pkgs "proxychains" {
+        example = "proxychains-ng";
       };
 
       chain = {
diff --git a/nixos/modules/programs/singularity.nix b/nixos/modules/programs/singularity.nix
index 79695b29beca..9fd37e1793a7 100644
--- a/nixos/modules/programs/singularity.nix
+++ b/nixos/modules/programs/singularity.nix
@@ -12,14 +12,8 @@ in
         Whether to install Singularity/Apptainer with system-level overriding such as SUID support.
       '';
     };
-    package = mkOption {
-      type = types.package;
-      default = pkgs.singularity;
-      defaultText = literalExpression "pkgs.singularity";
-      example = literalExpression "pkgs.apptainer";
-      description = mdDoc ''
-        Singularity/Apptainer package to override and install.
-      '';
+    package = mkPackageOption pkgs "singularity" {
+      example = "apptainer";
     };
     packageOverriden = mkOption {
       type = types.nullOr types.package;
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index 7c85d1e7c3d5..18eb3f938f3d 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -132,14 +132,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.openssh;
-        defaultText = literalExpression "pkgs.openssh";
-        description = lib.mdDoc ''
-          The package used for the openssh client and daemon.
-        '';
-      };
+      package = mkPackageOption pkgs "openssh" { };
 
       knownHosts = mkOption {
         default = {};
diff --git a/nixos/modules/programs/tsm-client.nix b/nixos/modules/programs/tsm-client.nix
index 41560544c2c7..6cb225d102de 100644
--- a/nixos/modules/programs/tsm-client.nix
+++ b/nixos/modules/programs/tsm-client.nix
@@ -5,7 +5,7 @@ let
   inherit (builtins) length map;
   inherit (lib.attrsets) attrNames filterAttrs hasAttr mapAttrs mapAttrsToList optionalAttrs;
   inherit (lib.modules) mkDefault mkIf;
-  inherit (lib.options) literalExpression mkEnableOption mkOption;
+  inherit (lib.options) literalExpression mkEnableOption mkOption mkPackageOption;
   inherit (lib.strings) concatLines optionalString toLower;
   inherit (lib.types) addCheck attrsOf lines nonEmptyStr nullOr package path port str strMatching submodule;
 
@@ -215,14 +215,9 @@ let
         TSM-depending packages used on the system.
       '';
     };
-    package = mkOption {
-      type = package;
-      default = pkgs.tsm-client;
-      defaultText = literalExpression "pkgs.tsm-client";
-      example = literalExpression "pkgs.tsm-client-withGui";
-      description = lib.mdDoc ''
-        The TSM client derivation to be
-        added to the system environment.
+    package = mkPackageOption pkgs "tsm-client" {
+      example = "tsm-client-withGui";
+      extraDescription = ''
         It will be used with `.override`
         to add paths to the client system-options file.
       '';
diff --git a/nixos/modules/programs/vim.nix b/nixos/modules/programs/vim.nix
index b12a45166d56..da2813f4bb53 100644
--- a/nixos/modules/programs/vim.nix
+++ b/nixos/modules/programs/vim.nix
@@ -15,14 +15,8 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.vim;
-      defaultText = literalExpression "pkgs.vim";
-      example = literalExpression "pkgs.vim-full";
-      description = lib.mdDoc ''
-        vim package to use.
-      '';
+    package = mkPackageOption pkgs "vim" {
+      example = "vim-full";
     };
   };
 
diff --git a/nixos/modules/programs/wayland/river.nix b/nixos/modules/programs/wayland/river.nix
index 71232a7d2618..ec59bd50a015 100644
--- a/nixos/modules/programs/wayland/river.nix
+++ b/nixos/modules/programs/wayland/river.nix
@@ -10,12 +10,9 @@ in {
   options.programs.river = {
     enable = mkEnableOption (lib.mdDoc "river, a dynamic tiling Wayland compositor");
 
-    package = mkOption {
-      type = with types; nullOr package;
-      default = pkgs.river;
-      defaultText = literalExpression "pkgs.river";
-      description = lib.mdDoc ''
-        River package to use.
+    package = mkPackageOption pkgs "river" {
+      nullable = true;
+      extraDescription = ''
         Set to `null` to not add any River package to your path.
         This should be done if you want to use the Home Manager River module to install River.
       '';
diff --git a/nixos/modules/programs/weylus.nix b/nixos/modules/programs/weylus.nix
index a5775f3b981c..f40dfd5c9613 100644
--- a/nixos/modules/programs/weylus.nix
+++ b/nixos/modules/programs/weylus.nix
@@ -26,12 +26,7 @@ in
       '';
     };
 
-    package = mkOption {
-      type = package;
-      default = pkgs.weylus;
-      defaultText = lib.literalExpression "pkgs.weylus";
-      description = lib.mdDoc "Weylus package to install.";
-    };
+    package = mkPackageOption pkgs "weylus" { };
   };
   config = mkIf cfg.enable {
     networking.firewall = mkIf cfg.openFirewall {
diff --git a/nixos/modules/programs/wireshark.nix b/nixos/modules/programs/wireshark.nix
index 834b0ba35695..c0dc349cca4a 100644
--- a/nixos/modules/programs/wireshark.nix
+++ b/nixos/modules/programs/wireshark.nix
@@ -16,13 +16,8 @@ in {
           setcap wrapper for 'dumpcap' for users in the 'wireshark' group.
         '';
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.wireshark-cli;
-        defaultText = literalExpression "pkgs.wireshark-cli";
-        description = lib.mdDoc ''
-          Which Wireshark package to install in the global environment.
-        '';
+      package = mkPackageOption pkgs "wireshark-cli" {
+        example = "wireshark";
       };
     };
   };
diff --git a/nixos/modules/programs/xonsh.nix b/nixos/modules/programs/xonsh.nix
index 167c953f5ffd..2ece772c929e 100644
--- a/nixos/modules/programs/xonsh.nix
+++ b/nixos/modules/programs/xonsh.nix
@@ -24,14 +24,8 @@ in
         type = types.bool;
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.xonsh;
-        defaultText = literalExpression "pkgs.xonsh";
-        example = literalExpression "pkgs.xonsh.override { extraPackages = ps: [ ps.requests ]; }";
-        description = lib.mdDoc ''
-          xonsh package to use.
-        '';
+      package = mkPackageOption pkgs "xonsh" {
+        example = "xonsh.override { extraPackages = ps: [ ps.requests ]; }";
       };
 
       config = mkOption {
diff --git a/nixos/modules/programs/zsh/oh-my-zsh.nix b/nixos/modules/programs/zsh/oh-my-zsh.nix
index 83eee1c88b3c..09c3bb974a50 100644
--- a/nixos/modules/programs/zsh/oh-my-zsh.nix
+++ b/nixos/modules/programs/zsh/oh-my-zsh.nix
@@ -46,15 +46,7 @@ in
           '';
         };
 
-        package = mkOption {
-          default = pkgs.oh-my-zsh;
-          defaultText = literalExpression "pkgs.oh-my-zsh";
-          description = lib.mdDoc ''
-            Package to install for `oh-my-zsh` usage.
-          '';
-
-          type = types.package;
-        };
+        package = mkPackageOption pkgs "oh-my-zsh" { };
 
         plugins = mkOption {
           default = [];
diff --git a/nixos/modules/programs/zsh/zsh-autoenv.nix b/nixos/modules/programs/zsh/zsh-autoenv.nix
index be93c96b2bc8..0894bfc3fdda 100644
--- a/nixos/modules/programs/zsh/zsh-autoenv.nix
+++ b/nixos/modules/programs/zsh/zsh-autoenv.nix
@@ -8,15 +8,7 @@ in {
   options = {
     programs.zsh.zsh-autoenv = {
       enable = mkEnableOption (lib.mdDoc "zsh-autoenv");
-      package = mkOption {
-        default = pkgs.zsh-autoenv;
-        defaultText = literalExpression "pkgs.zsh-autoenv";
-        description = lib.mdDoc ''
-          Package to install for `zsh-autoenv` usage.
-        '';
-
-        type = types.package;
-      };
+      package = mkPackageOption pkgs "zsh-autoenv" { };
     };
   };
 
diff --git a/nixos/modules/security/please.nix b/nixos/modules/security/please.nix
index 88bb9cba2bfc..ff4bfc9f1be1 100644
--- a/nixos/modules/security/please.nix
+++ b/nixos/modules/security/please.nix
@@ -13,14 +13,7 @@ in
       file as another user
     '');
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.please;
-      defaultText = literalExpression "pkgs.please";
-      description = mdDoc ''
-        Which package to use for {command}`please`.
-      '';
-    };
+    package = mkPackageOption pkgs "please" { };
 
     wheelNeedsPassword = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/admin/meshcentral.nix b/nixos/modules/services/admin/meshcentral.nix
index 22f31e952622..d056356568da 100644
--- a/nixos/modules/services/admin/meshcentral.nix
+++ b/nixos/modules/services/admin/meshcentral.nix
@@ -6,12 +6,7 @@ let
 in with lib; {
   options.services.meshcentral = with types; {
     enable = mkEnableOption (lib.mdDoc "MeshCentral computer management server");
-    package = mkOption {
-      description = lib.mdDoc "MeshCentral package to use. Replacing this may be necessary to add dependencies for extra functionality.";
-      type = types.package;
-      default = pkgs.meshcentral;
-      defaultText = literalExpression "pkgs.meshcentral";
-    };
+    package = mkPackageOption pkgs "meshcentral" { };
     settings = mkOption {
       description = lib.mdDoc ''
         Settings for MeshCentral. Refer to upstream documentation for details:
diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix
index 11dabf0b51c8..7dce9d242916 100644
--- a/nixos/modules/services/amqp/rabbitmq.nix
+++ b/nixos/modules/services/amqp/rabbitmq.nix
@@ -26,14 +26,7 @@ in
         '';
       };
 
-      package = mkOption {
-        default = pkgs.rabbitmq-server;
-        type = types.package;
-        defaultText = literalExpression "pkgs.rabbitmq-server";
-        description = lib.mdDoc ''
-          Which rabbitmq package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "rabbitmq-server" { };
 
       listenAddress = mkOption {
         default = "127.0.0.1";
diff --git a/nixos/modules/services/audio/botamusique.nix b/nixos/modules/services/audio/botamusique.nix
index 5d3f7db12bc9..42227cb14722 100644
--- a/nixos/modules/services/audio/botamusique.nix
+++ b/nixos/modules/services/audio/botamusique.nix
@@ -14,12 +14,7 @@ in
   options.services.botamusique = {
     enable = mkEnableOption (lib.mdDoc "botamusique, a bot to play audio streams on mumble");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.botamusique;
-      defaultText = literalExpression "pkgs.botamusique";
-      description = lib.mdDoc "The botamusique package to use.";
-    };
+    package = mkPackageOption pkgs "botamusique" { };
 
     settings = mkOption {
       type = with types; submodule {
diff --git a/nixos/modules/services/audio/jack.nix b/nixos/modules/services/audio/jack.nix
index b51f2a78c983..3869bd974cce 100644
--- a/nixos/modules/services/audio/jack.nix
+++ b/nixos/modules/services/audio/jack.nix
@@ -20,16 +20,11 @@ in {
           JACK Audio Connection Kit. You need to add yourself to the "jackaudio" group
         '');
 
-        package = mkOption {
+        package = mkPackageOption pkgs "jack2" {
+          example = "jack1";
+        } // {
           # until jack1 promiscuous mode is fixed
           internal = true;
-          type = types.package;
-          default = pkgs.jack2;
-          defaultText = literalExpression "pkgs.jack2";
-          example = literalExpression "pkgs.jack1";
-          description = lib.mdDoc ''
-            The JACK package to use.
-          '';
         };
 
         extraOptions = mkOption {
diff --git a/nixos/modules/services/audio/jmusicbot.nix b/nixos/modules/services/audio/jmusicbot.nix
index 348c7b25682e..fd1d4da19284 100644
--- a/nixos/modules/services/audio/jmusicbot.nix
+++ b/nixos/modules/services/audio/jmusicbot.nix
@@ -9,12 +9,7 @@ in
     services.jmusicbot = {
       enable = mkEnableOption (lib.mdDoc "jmusicbot, a Discord music bot that's easy to set up and run yourself");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.jmusicbot;
-        defaultText = literalExpression "pkgs.jmusicbot";
-        description = lib.mdDoc "JMusicBot package to use";
-      };
+      package = mkPackageOption pkgs "jmusicbot" { };
 
       stateDir = mkOption {
         type = types.path;
diff --git a/nixos/modules/services/audio/slimserver.nix b/nixos/modules/services/audio/slimserver.nix
index cdd9d551c501..73cda08c5742 100644
--- a/nixos/modules/services/audio/slimserver.nix
+++ b/nixos/modules/services/audio/slimserver.nix
@@ -19,12 +19,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.slimserver;
-        defaultText = literalExpression "pkgs.slimserver";
-        description = lib.mdDoc "Slimserver package to use.";
-      };
+      package = mkPackageOption pkgs "slimserver" { };
 
       dataDir = mkOption {
         type = types.path;
diff --git a/nixos/modules/services/backup/postgresql-wal-receiver.nix b/nixos/modules/services/backup/postgresql-wal-receiver.nix
index 773dc0ba447d..332a32d37052 100644
--- a/nixos/modules/services/backup/postgresql-wal-receiver.nix
+++ b/nixos/modules/services/backup/postgresql-wal-receiver.nix
@@ -5,12 +5,8 @@ with lib;
 let
   receiverSubmodule = {
     options = {
-      postgresqlPackage = mkOption {
-        type = types.package;
-        example = literalExpression "pkgs.postgresql_15";
-        description = lib.mdDoc ''
-          PostgreSQL package to use.
-        '';
+      postgresqlPackage = mkPackageOption pkgs "postgresql" {
+        example = "postgresql_15";
       };
 
       directory = mkOption {
diff --git a/nixos/modules/services/backup/restic-rest-server.nix b/nixos/modules/services/backup/restic-rest-server.nix
index 37a6150c99d3..105a05caf304 100644
--- a/nixos/modules/services/backup/restic-rest-server.nix
+++ b/nixos/modules/services/backup/restic-rest-server.nix
@@ -57,12 +57,7 @@ in
       '';
     };
 
-    package = mkOption {
-      default = pkgs.restic-rest-server;
-      defaultText = literalExpression "pkgs.restic-rest-server";
-      type = types.package;
-      description = lib.mdDoc "Restic REST server package to use.";
-    };
+    package = mkPackageOption pkgs "restic-rest-server" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix
index 87595f39796d..e3eb504e0adf 100644
--- a/nixos/modules/services/backup/restic.nix
+++ b/nixos/modules/services/backup/restic.nix
@@ -245,14 +245,7 @@ in
           '';
         };
 
-        package = mkOption {
-          type = types.package;
-          default = pkgs.restic;
-          defaultText = literalExpression "pkgs.restic";
-          description = lib.mdDoc ''
-            Restic package to use.
-          '';
-        };
+        package = mkPackageOption pkgs "restic" { };
 
         createWrapper = lib.mkOption {
           type = lib.types.bool;
diff --git a/nixos/modules/services/backup/zrepl.nix b/nixos/modules/services/backup/zrepl.nix
index 1d3afa3eda05..8475a347429e 100644
--- a/nixos/modules/services/backup/zrepl.nix
+++ b/nixos/modules/services/backup/zrepl.nix
@@ -13,12 +13,7 @@ in
     services.zrepl = {
       enable = mkEnableOption (lib.mdDoc "zrepl");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.zrepl;
-        defaultText = literalExpression "pkgs.zrepl";
-        description = lib.mdDoc "Which package to use for zrepl";
-      };
+      package = mkPackageOption pkgs "zrepl" { };
 
       settings = mkOption {
         default = { };
diff --git a/nixos/modules/services/blockchain/ethereum/geth.nix b/nixos/modules/services/blockchain/ethereum/geth.nix
index d12516ca2f24..f07dfa4dc711 100644
--- a/nixos/modules/services/blockchain/ethereum/geth.nix
+++ b/nixos/modules/services/blockchain/ethereum/geth.nix
@@ -135,12 +135,7 @@ let
         default = [];
       };
 
-      package = mkOption {
-        default = pkgs.go-ethereum.geth;
-        defaultText = literalExpression "pkgs.go-ethereum.geth";
-        type = types.package;
-        description = lib.mdDoc "Package to use as Go Ethereum node.";
-      };
+      package = mkPackageOption pkgs [ "go-ethereum" "geth" ] { };
     };
   };
 in
diff --git a/nixos/modules/services/cluster/corosync/default.nix b/nixos/modules/services/cluster/corosync/default.nix
index 7ef17c46b81e..477ffbcdb7c7 100644
--- a/nixos/modules/services/cluster/corosync/default.nix
+++ b/nixos/modules/services/cluster/corosync/default.nix
@@ -9,12 +9,7 @@ in
   options.services.corosync = {
     enable = mkEnableOption (lib.mdDoc "corosync");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.corosync;
-      defaultText = literalExpression "pkgs.corosync";
-      description = lib.mdDoc "Package that should be used for corosync.";
-    };
+    package = mkPackageOption pkgs "corosync" { };
 
     clusterName = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/cluster/hadoop/default.nix b/nixos/modules/services/cluster/hadoop/default.nix
index ff6b4d5588b1..6fa91d2f047e 100644
--- a/nixos/modules/services/cluster/hadoop/default.nix
+++ b/nixos/modules/services/cluster/hadoop/default.nix
@@ -199,12 +199,7 @@ with lib;
 
     gatewayRole.enable = mkEnableOption (lib.mdDoc "gateway role for deploying hadoop configs");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.hadoop;
-      defaultText = literalExpression "pkgs.hadoop";
-      description = lib.mdDoc "";
-    };
+    package = mkPackageOption pkgs "hadoop" { };
   };
 
 
diff --git a/nixos/modules/services/cluster/hadoop/hbase.nix b/nixos/modules/services/cluster/hadoop/hbase.nix
index a39da2a84eca..6801e505db64 100644
--- a/nixos/modules/services/cluster/hadoop/hbase.nix
+++ b/nixos/modules/services/cluster/hadoop/hbase.nix
@@ -134,12 +134,7 @@ in
 
     hbase = {
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.hbase;
-        defaultText = literalExpression "pkgs.hbase";
-        description = mdDoc "HBase package";
-      };
+      package = mkPackageOption pkgs "hbase" { };
 
       rootdir = mkOption {
         description = mdDoc ''
diff --git a/nixos/modules/services/cluster/k3s/default.nix b/nixos/modules/services/cluster/k3s/default.nix
index 72b2f992a339..dc71f1372d7a 100644
--- a/nixos/modules/services/cluster/k3s/default.nix
+++ b/nixos/modules/services/cluster/k3s/default.nix
@@ -15,12 +15,7 @@ in
   options.services.k3s = {
     enable = mkEnableOption (lib.mdDoc "k3s");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.k3s;
-      defaultText = literalExpression "pkgs.k3s";
-      description = lib.mdDoc "Package that should be used for k3s";
-    };
+    package = mkPackageOption pkgs "k3s" { };
 
     role = mkOption {
       description = lib.mdDoc ''
diff --git a/nixos/modules/services/cluster/kubernetes/default.nix b/nixos/modules/services/cluster/kubernetes/default.nix
index f5374fc71942..3fb916c76971 100644
--- a/nixos/modules/services/cluster/kubernetes/default.nix
+++ b/nixos/modules/services/cluster/kubernetes/default.nix
@@ -122,12 +122,7 @@ in {
       type = types.listOf (types.enum ["master" "node"]);
     };
 
-    package = mkOption {
-      description = lib.mdDoc "Kubernetes package to use.";
-      type = types.package;
-      default = pkgs.kubernetes;
-      defaultText = literalExpression "pkgs.kubernetes";
-    };
+    package = mkPackageOption pkgs "kubernetes" { };
 
     kubeconfig = mkKubeConfigOptions "Default kubeconfig";
 
diff --git a/nixos/modules/services/cluster/pacemaker/default.nix b/nixos/modules/services/cluster/pacemaker/default.nix
index 0f37f4b754fe..255bb107796f 100644
--- a/nixos/modules/services/cluster/pacemaker/default.nix
+++ b/nixos/modules/services/cluster/pacemaker/default.nix
@@ -9,12 +9,7 @@ in
   options.services.pacemaker = {
     enable = mkEnableOption (lib.mdDoc "pacemaker");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.pacemaker;
-      defaultText = literalExpression "pkgs.pacemaker";
-      description = lib.mdDoc "Package that should be used for pacemaker.";
-    };
+    package = mkPackageOption pkgs "pacemaker" { };
   };
 
   # implementation
diff --git a/nixos/modules/services/cluster/spark/default.nix b/nixos/modules/services/cluster/spark/default.nix
index bf39c5537332..2e3914a734be 100644
--- a/nixos/modules/services/cluster/spark/default.nix
+++ b/nixos/modules/services/cluster/spark/default.nix
@@ -77,20 +77,18 @@ with lib;
         description = lib.mdDoc "Spark log directory.";
         default = "/var/log/spark";
       };
-      package = mkOption {
-        type = types.package;
-        description = lib.mdDoc "Spark package.";
-        default = pkgs.spark;
-        defaultText = literalExpression "pkgs.spark";
-        example = literalExpression ''pkgs.spark.overrideAttrs (super: rec {
-          pname = "spark";
-          version = "2.4.4";
+      package = mkPackageOption pkgs "spark" {
+        example = ''
+          spark.overrideAttrs (super: rec {
+            pname = "spark";
+            version = "2.4.4";
 
-          src = pkgs.fetchzip {
-            url    = "mirror://apache/spark/"''${pname}-''${version}/''${pname}-''${version}-bin-without-hadoop.tgz";
-            sha256 = "1a9w5k0207fysgpxx6db3a00fs5hdc2ncx99x4ccy2s0v5ndc66g";
-          };
-        })'';
+            src = pkgs.fetchzip {
+              url    = "mirror://apache/spark/"''${pname}-''${version}/''${pname}-''${version}-bin-without-hadoop.tgz";
+              sha256 = "1a9w5k0207fysgpxx6db3a00fs5hdc2ncx99x4ccy2s0v5ndc66g";
+            };
+          })
+        '';
       };
     };
   };
diff --git a/nixos/modules/services/computing/boinc/client.nix b/nixos/modules/services/computing/boinc/client.nix
index ff16795c8208..c2132149a3f5 100644
--- a/nixos/modules/services/computing/boinc/client.nix
+++ b/nixos/modules/services/computing/boinc/client.nix
@@ -27,14 +27,8 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.boinc;
-        defaultText = literalExpression "pkgs.boinc";
-        example = literalExpression "pkgs.boinc-headless";
-        description = lib.mdDoc ''
-          Which BOINC package to use.
-        '';
+      package = mkPackageOption pkgs "boinc" {
+        example = "boinc-headless";
       };
 
       dataDir = mkOption {
diff --git a/nixos/modules/services/computing/foldingathome/client.nix b/nixos/modules/services/computing/foldingathome/client.nix
index a4e79fd1c141..09f31cda769c 100644
--- a/nixos/modules/services/computing/foldingathome/client.nix
+++ b/nixos/modules/services/computing/foldingathome/client.nix
@@ -20,14 +20,7 @@ in
   options.services.foldingathome = {
     enable = mkEnableOption (lib.mdDoc "Folding@home client");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.fahclient;
-      defaultText = literalExpression "pkgs.fahclient";
-      description = lib.mdDoc ''
-        Which Folding@home client to use.
-      '';
-    };
+    package = mkPackageOption pkgs "fahclient" { };
 
     user = mkOption {
       type = types.nullOr types.str;
diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix
index 1cbe7b893f83..9212fe39fd83 100644
--- a/nixos/modules/services/computing/slurm/slurm.nix
+++ b/nixos/modules/services/computing/slurm/slurm.nix
@@ -131,14 +131,10 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
+      package = mkPackageOption pkgs "slurm" {
+        example = "slurm-full";
+      } // {
         default = pkgs.slurm.override { enableX11 = ! cfg.enableSrunX11; };
-        defaultText = literalExpression "pkgs.slurm";
-        example = literalExpression "pkgs.slurm-full";
-        description = lib.mdDoc ''
-          The package to use for slurm binaries.
-        '';
       };
 
       controlMachine = mkOption {
diff --git a/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixos/modules/services/continuous-integration/buildbot/master.nix
index 9a89745055f0..56abeda3a5cd 100644
--- a/nixos/modules/services/continuous-integration/buildbot/master.nix
+++ b/nixos/modules/services/continuous-integration/buildbot/master.nix
@@ -229,12 +229,8 @@ in {
         description = lib.mdDoc "Specifies port number on which the buildbot HTTP interface listens.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.buildbot-full;
-        defaultText = literalExpression "pkgs.buildbot-full";
-        description = lib.mdDoc "Package to use for buildbot.";
-        example = literalExpression "pkgs.buildbot";
+      package = mkPackageOption pkgs "buildbot-full" {
+        example = "buildbot";
       };
 
       packages = mkOption {
diff --git a/nixos/modules/services/continuous-integration/buildbot/worker.nix b/nixos/modules/services/continuous-integration/buildbot/worker.nix
index 7e78b8935f81..b906788209b1 100644
--- a/nixos/modules/services/continuous-integration/buildbot/worker.nix
+++ b/nixos/modules/services/continuous-integration/buildbot/worker.nix
@@ -128,12 +128,8 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.buildbot-worker;
-        defaultText = literalExpression "pkgs.python3Packages.buildbot-worker";
-        description = lib.mdDoc "Package to use for buildbot worker.";
-        example = literalExpression "pkgs.python2Packages.buildbot-worker";
+      package = mkPackageOption pkgs "python3Packages.buildbot-worker" {
+        example = "python2Packages.buildbot-worker";
       };
 
       packages = mkOption {
diff --git a/nixos/modules/services/continuous-integration/github-runner/options.nix b/nixos/modules/services/continuous-integration/github-runner/options.nix
index f2887c7711b3..2335826e8b66 100644
--- a/nixos/modules/services/continuous-integration/github-runner/options.nix
+++ b/nixos/modules/services/continuous-integration/github-runner/options.nix
@@ -161,14 +161,7 @@ with lib;
     default = {};
   };
 
-  package = mkOption {
-    type = types.package;
-    description = lib.mdDoc ''
-      Which github-runner derivation to use.
-    '';
-    default = pkgs.github-runner;
-    defaultText = literalExpression "pkgs.github-runner";
-  };
+  package = mkPackageOption pkgs "github-runner" { };
 
   ephemeral = mkOption {
     type = types.bool;
diff --git a/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixos/modules/services/continuous-integration/gitlab-runner.nix
index 10a2fe8a44dd..05b2449936bc 100644
--- a/nixos/modules/services/continuous-integration/gitlab-runner.nix
+++ b/nixos/modules/services/continuous-integration/gitlab-runner.nix
@@ -195,12 +195,8 @@ in {
         Time to wait until a graceful shutdown is turned into a forceful one.
       '';
     };
-    package = mkOption {
-      type = types.package;
-      default = pkgs.gitlab-runner;
-      defaultText = literalExpression "pkgs.gitlab-runner";
-      example = literalExpression "pkgs.gitlab-runner_1_11";
-      description = lib.mdDoc "Gitlab Runner package to use.";
+    package = mkPackageOption pkgs "gitlab-runner" {
+      example = "gitlab-runner_1_11";
     };
     extraPackages = mkOption {
       type = types.listOf types.package;
diff --git a/nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix b/nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix
index ea9b5ffbf43c..7d33989044de 100644
--- a/nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix
+++ b/nixos/modules/services/continuous-integration/hercules-ci-agent/common.nix
@@ -16,7 +16,7 @@ let
     mkRemovedOptionModule
     mkRenamedOptionModule
     types
-
+    mkPackageOption
     ;
 
   cfg = config.services.hercules-ci-agent;
@@ -45,14 +45,7 @@ in
         Support is available at [help@hercules-ci.com](mailto:help@hercules-ci.com).
       '';
     };
-    package = mkOption {
-      description = lib.mdDoc ''
-        Package containing the bin/hercules-ci-agent executable.
-      '';
-      type = types.package;
-      default = pkgs.hercules-ci-agent;
-      defaultText = literalExpression "pkgs.hercules-ci-agent";
-    };
+    package = mkPackageOption pkgs "hercules-ci-agent" { };
     settings = mkOption {
       description = lib.mdDoc ''
         These settings are written to the `agent.toml` file.
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
index 83078706fcae..46b03bba37be 100644
--- a/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -97,12 +97,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.hydra_unstable;
-        defaultText = literalExpression "pkgs.hydra_unstable";
-        description = lib.mdDoc "The Hydra package.";
-      };
+      package = mkPackageOption pkgs "hydra_unstable" { };
 
       hydraURL = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix
index e4d54b0cb0f4..e96743784e04 100644
--- a/nixos/modules/services/continuous-integration/jenkins/default.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/default.nix
@@ -79,12 +79,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        default = pkgs.jenkins;
-        defaultText = literalExpression "pkgs.jenkins";
-        type = types.package;
-        description = lib.mdDoc "Jenkins package to use.";
-      };
+      package = mkPackageOption pkgs "jenkins" { };
 
       packages = mkOption {
         default = [ pkgs.stdenv pkgs.git pkgs.jdk17 config.programs.ssh.package pkgs.nix ];
diff --git a/nixos/modules/services/continuous-integration/jenkins/slave.nix b/nixos/modules/services/continuous-integration/jenkins/slave.nix
index 9b86917ab380..82d34a058c57 100644
--- a/nixos/modules/services/continuous-integration/jenkins/slave.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/slave.nix
@@ -47,14 +47,7 @@ in {
         '';
       };
 
-      javaPackage = mkOption {
-        default = pkgs.jdk;
-        defaultText = literalExpression "pkgs.jdk";
-        description = lib.mdDoc ''
-          Java package to install.
-        '';
-        type = types.package;
-      };
+      javaPackage = mkPackageOption pkgs "jdk" { };
     };
   };
 
diff --git a/nixos/modules/services/databases/aerospike.nix b/nixos/modules/services/databases/aerospike.nix
index 21df4cd0577b..373c8f4bffb0 100644
--- a/nixos/modules/services/databases/aerospike.nix
+++ b/nixos/modules/services/databases/aerospike.nix
@@ -41,12 +41,7 @@ in
     services.aerospike = {
       enable = mkEnableOption (lib.mdDoc "Aerospike server");
 
-      package = mkOption {
-        default = pkgs.aerospike;
-        defaultText = literalExpression "pkgs.aerospike";
-        type = types.package;
-        description = lib.mdDoc "Which Aerospike derivation to use";
-      };
+      package = mkPackageOption pkgs "aerospike" { };
 
       workDir = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/databases/cassandra.nix b/nixos/modules/services/databases/cassandra.nix
index cd816ffaf0dd..adf7213dd13f 100644
--- a/nixos/modules/services/databases/cassandra.nix
+++ b/nixos/modules/services/databases/cassandra.nix
@@ -11,6 +11,7 @@ let
     recursiveUpdate
     mdDoc
     mkEnableOption
+    mkPackageOption
     mkIf
     mkOption
     types
@@ -155,14 +156,8 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.cassandra;
-      defaultText = literalExpression "pkgs.cassandra";
-      example = literalExpression "pkgs.cassandra_3_11";
-      description = mdDoc ''
-        The Apache Cassandra package to use.
-      '';
+    package = mkPackageOption pkgs "cassandra" {
+      example = "cassandra_3_11";
     };
 
     jvmOpts = mkOption {
diff --git a/nixos/modules/services/databases/clickhouse.nix b/nixos/modules/services/databases/clickhouse.nix
index dca352ef72fe..288046677721 100644
--- a/nixos/modules/services/databases/clickhouse.nix
+++ b/nixos/modules/services/databases/clickhouse.nix
@@ -13,14 +13,7 @@ with lib;
 
       enable = mkEnableOption (lib.mdDoc "ClickHouse database server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.clickhouse;
-        defaultText = lib.literalExpression "pkgs.clickhouse";
-        description = lib.mdDoc ''
-          ClickHouse package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "clickhouse" { };
 
     };
 
diff --git a/nixos/modules/services/databases/cockroachdb.nix b/nixos/modules/services/databases/cockroachdb.nix
index ff77d30588fe..789f086158db 100644
--- a/nixos/modules/services/databases/cockroachdb.nix
+++ b/nixos/modules/services/databases/cockroachdb.nix
@@ -145,13 +145,8 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.cockroachdb;
-        defaultText = literalExpression "pkgs.cockroachdb";
-        description = lib.mdDoc ''
-          The CockroachDB derivation to use for running the service.
-
+      package = mkPackageOption pkgs "cockroachdb" {
+        extraDescription = ''
           This would primarily be useful to enable Enterprise Edition features
           in your own custom CockroachDB build (Nixpkgs CockroachDB binaries
           only contain open source features and open source code).
diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix
index bfecfbb3664f..72212c390413 100644
--- a/nixos/modules/services/databases/couchdb.nix
+++ b/nixos/modules/services/databases/couchdb.nix
@@ -36,14 +36,7 @@ in {
 
       enable = mkEnableOption (lib.mdDoc "CouchDB Server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.couchdb3;
-        defaultText = literalExpression "pkgs.couchdb3";
-        description = lib.mdDoc ''
-          CouchDB package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "couchdb3" { };
 
       adminUser = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/databases/firebird.nix b/nixos/modules/services/databases/firebird.nix
index 3927c81d953d..36c12eaaf5f1 100644
--- a/nixos/modules/services/databases/firebird.nix
+++ b/nixos/modules/services/databases/firebird.nix
@@ -42,13 +42,9 @@ in
 
       enable = mkEnableOption (lib.mdDoc "the Firebird super server");
 
-      package = mkOption {
-        default = pkgs.firebird;
-        defaultText = literalExpression "pkgs.firebird";
-        type = types.package;
-        example = literalExpression "pkgs.firebird_3";
-        description = lib.mdDoc ''
-          Which Firebird package to be installed: `pkgs.firebird_3`
+      package = mkPackageOption pkgs "firebird" {
+        example = "firebird_3";
+        extraDescription = ''
           For SuperServer use override: `pkgs.firebird_3.override { superServer = true; };`
         '';
       };
diff --git a/nixos/modules/services/databases/hbase-standalone.nix b/nixos/modules/services/databases/hbase-standalone.nix
index 1ee73ec8d1ff..08ae7625d50a 100644
--- a/nixos/modules/services/databases/hbase-standalone.nix
+++ b/nixos/modules/services/databases/hbase-standalone.nix
@@ -46,15 +46,7 @@ in {
         Do not use this configuration for production nor for evaluating HBase performance.
       '');
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.hbase;
-        defaultText = literalExpression "pkgs.hbase";
-        description = lib.mdDoc ''
-          HBase package to use.
-        '';
-      };
-
+      package = mkPackageOption pkgs "hbase" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/databases/influxdb.nix b/nixos/modules/services/databases/influxdb.nix
index b3361d2014ca..34b4139e7c58 100644
--- a/nixos/modules/services/databases/influxdb.nix
+++ b/nixos/modules/services/databases/influxdb.nix
@@ -116,12 +116,7 @@ in
         type = types.bool;
       };
 
-      package = mkOption {
-        default = pkgs.influxdb;
-        defaultText = literalExpression "pkgs.influxdb";
-        description = lib.mdDoc "Which influxdb derivation to use";
-        type = types.package;
-      };
+      package = mkPackageOption pkgs "influxdb" { };
 
       user = mkOption {
         default = "influxdb";
diff --git a/nixos/modules/services/databases/influxdb2.nix b/nixos/modules/services/databases/influxdb2.nix
index 3740cd01b5dc..2a67d87d4bbb 100644
--- a/nixos/modules/services/databases/influxdb2.nix
+++ b/nixos/modules/services/databases/influxdb2.nix
@@ -19,6 +19,7 @@ let
     mapAttrsToList
     mdDoc
     mkEnableOption
+    mkPackageOption
     mkIf
     mkOption
     nameValuePair
@@ -278,12 +279,7 @@ in
     services.influxdb2 = {
       enable = mkEnableOption (mdDoc "the influxdb2 server");
 
-      package = mkOption {
-        default = pkgs.influxdb2-server;
-        defaultText = literalExpression "pkgs.influxdb2";
-        description = mdDoc "influxdb2 derivation to use.";
-        type = types.package;
-      };
+      package = mkPackageOption pkgs "influxdb2" { };
 
       settings = mkOption {
         default = { };
diff --git a/nixos/modules/services/databases/monetdb.nix b/nixos/modules/services/databases/monetdb.nix
index 5573b530a913..1dddeda0959c 100644
--- a/nixos/modules/services/databases/monetdb.nix
+++ b/nixos/modules/services/databases/monetdb.nix
@@ -14,12 +14,7 @@ in {
 
       enable = mkEnableOption (lib.mdDoc "the MonetDB database server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.monetdb;
-        defaultText = literalExpression "pkgs.monetdb";
-        description = lib.mdDoc "MonetDB package to use.";
-      };
+      package = mkPackageOption pkgs "monetdb" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix
index 8f3be1492e9e..f10364bc76c1 100644
--- a/nixos/modules/services/databases/mongodb.nix
+++ b/nixos/modules/services/databases/mongodb.nix
@@ -31,14 +31,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "the MongoDB server");
 
-      package = mkOption {
-        default = pkgs.mongodb;
-        defaultText = literalExpression "pkgs.mongodb";
-        type = types.package;
-        description = lib.mdDoc ''
-          Which MongoDB derivation to use.
-        '';
-      };
+      package = mkPackageOption pkgs "mongodb" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix
index 090502424028..56b916ee3758 100644
--- a/nixos/modules/services/databases/neo4j.nix
+++ b/nixos/modules/services/databases/neo4j.nix
@@ -174,14 +174,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.neo4j;
-      defaultText = literalExpression "pkgs.neo4j";
-      description = lib.mdDoc ''
-        Neo4j package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "neo4j" { };
 
     readOnly = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix
index cba3442023cb..a7a0909f55e1 100644
--- a/nixos/modules/services/databases/openldap.nix
+++ b/nixos/modules/services/databases/openldap.nix
@@ -91,13 +91,8 @@ in {
         description = lib.mdDoc "Whether to enable the ldap server.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.openldap;
-        defaultText = literalExpression "pkgs.openldap";
-        description = lib.mdDoc ''
-          OpenLDAP package to use.
-
+      package = mkPackageOption pkgs "openldap" {
+        extraDescription = ''
           This can be used to, for example, set an OpenLDAP package
           with custom overrides to enable modules or other
           functionality.
diff --git a/nixos/modules/services/databases/opentsdb.nix b/nixos/modules/services/databases/opentsdb.nix
index 288b716fce03..25f413db809f 100644
--- a/nixos/modules/services/databases/opentsdb.nix
+++ b/nixos/modules/services/databases/opentsdb.nix
@@ -17,14 +17,7 @@ in {
 
       enable = mkEnableOption (lib.mdDoc "OpenTSDB");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.opentsdb;
-        defaultText = literalExpression "pkgs.opentsdb";
-        description = lib.mdDoc ''
-          OpenTSDB package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "opentsdb" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/databases/pgbouncer.nix b/nixos/modules/services/databases/pgbouncer.nix
index 1aec03c114d1..65b287e84442 100644
--- a/nixos/modules/services/databases/pgbouncer.nix
+++ b/nixos/modules/services/databases/pgbouncer.nix
@@ -82,14 +82,7 @@ in {
 
     enable = mkEnableOption (lib.mdDoc "PostgreSQL connection pooler");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.pgbouncer;
-      defaultText = literalExpression "pkgs.pgbouncer";
-      description = lib.mdDoc ''
-        The pgbouncer package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "pgbouncer" { };
 
     openFirewall = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/databases/pgmanage.nix b/nixos/modules/services/databases/pgmanage.nix
index a0933a5ffc45..4b963aee4640 100644
--- a/nixos/modules/services/databases/pgmanage.nix
+++ b/nixos/modules/services/databases/pgmanage.nix
@@ -46,14 +46,7 @@ in {
   options.services.pgmanage = {
     enable = mkEnableOption (lib.mdDoc "PostgreSQL Administration for the web");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.pgmanage;
-      defaultText = literalExpression "pkgs.pgmanage";
-      description = lib.mdDoc ''
-        The pgmanage package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "pgmanage" { };
 
     connections = mkOption {
       type = types.attrsOf types.str;
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index d69ffff7b47b..690f2d85a4c9 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -53,12 +53,8 @@ in
 
       enableJIT = mkEnableOption (lib.mdDoc "JIT support");
 
-      package = mkOption {
-        type = types.package;
-        example = literalExpression "pkgs.postgresql_15";
-        description = lib.mdDoc ''
-          PostgreSQL package to use.
-        '';
+      package = mkPackageOption pkgs "postgresql" {
+        example = "postgresql_15";
       };
 
       port = mkOption {
diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix
index 4a5c19240ec6..2e644895a260 100644
--- a/nixos/modules/services/databases/redis.nix
+++ b/nixos/modules/services/databases/redis.nix
@@ -54,12 +54,7 @@ in {
   options = {
 
     services.redis = {
-      package = mkOption {
-        type = types.package;
-        default = pkgs.redis;
-        defaultText = literalExpression "pkgs.redis";
-        description = lib.mdDoc "Which Redis derivation to use.";
-      };
+      package = mkPackageOption pkgs "redis" { };
 
       vmOverCommit = mkEnableOption (lib.mdDoc ''
         setting of vm.overcommit_memory to 1
diff --git a/nixos/modules/services/databases/surrealdb.nix b/nixos/modules/services/databases/surrealdb.nix
index e1a1faed1f8f..55216d022d1c 100644
--- a/nixos/modules/services/databases/surrealdb.nix
+++ b/nixos/modules/services/databases/surrealdb.nix
@@ -10,14 +10,7 @@ in {
     services.surrealdb = {
       enable = mkEnableOption (lib.mdDoc "SurrealDB, a scalable, distributed, collaborative, document-graph database, for the realtime web");
 
-      package = mkOption {
-        default = pkgs.surrealdb;
-        defaultText = literalExpression "pkgs.surrealdb";
-        type = types.package;
-        description = lib.mdDoc ''
-          Which surrealdb derivation to use.
-        '';
-      };
+      package = mkPackageOption pkgs "surrealdb" { };
 
       dbPath = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/databases/victoriametrics.nix b/nixos/modules/services/databases/victoriametrics.nix
index 638066a42dbd..0ad2028c95b0 100644
--- a/nixos/modules/services/databases/victoriametrics.nix
+++ b/nixos/modules/services/databases/victoriametrics.nix
@@ -3,14 +3,7 @@ let cfg = config.services.victoriametrics; in
 {
   options.services.victoriametrics = with lib; {
     enable = mkEnableOption (lib.mdDoc "victoriametrics");
-    package = mkOption {
-      type = types.package;
-      default = pkgs.victoriametrics;
-      defaultText = literalExpression "pkgs.victoriametrics";
-      description = lib.mdDoc ''
-        The VictoriaMetrics distribution to use.
-      '';
-    };
+    package = mkPackageOption pkgs "victoriametrics" { };
     listenAddress = mkOption {
       default = ":8428";
       type = types.str;
diff --git a/nixos/modules/services/desktops/deepin/app-services.nix b/nixos/modules/services/desktops/deepin/app-services.nix
index 4592bc7bb340..a6c33af03e95 100644
--- a/nixos/modules/services/desktops/deepin/app-services.nix
+++ b/nixos/modules/services/desktops/deepin/app-services.nix
@@ -25,8 +25,17 @@ with lib;
 
   config = mkIf config.services.deepin.app-services.enable {
 
-    environment.systemPackages = [ pkgs.deepin.dde-app-services ];
+    users.groups.dde-dconfig-daemon = { };
+    users.users.dde-dconfig-daemon = {
+      description = "Dconfig daemon user";
+      home = "/var/lib/dde-dconfig-daemon";
+      createHome = true;
+      group = "dde-dconfig-daemon";
+      isSystemUser = true;
+    };
 
+    environment.systemPackages = [ pkgs.deepin.dde-app-services ];
+    systemd.packages = [ pkgs.deepin.dde-app-services ];
     services.dbus.packages = [ pkgs.deepin.dde-app-services ];
 
     environment.pathsToLink = [ "/share/dsg" ];
diff --git a/nixos/modules/services/desktops/gvfs.nix b/nixos/modules/services/desktops/gvfs.nix
index 7e15b433fcc2..a4770d703f54 100644
--- a/nixos/modules/services/desktops/gvfs.nix
+++ b/nixos/modules/services/desktops/gvfs.nix
@@ -32,12 +32,7 @@ in
       enable = mkEnableOption (lib.mdDoc "GVfs, a userspace virtual filesystem");
 
       # gvfs can be built with multiple configurations
-      package = mkOption {
-        type = types.package;
-        default = pkgs.gnome.gvfs;
-        defaultText = literalExpression "pkgs.gnome.gvfs";
-        description = lib.mdDoc "Which GVfs package to use.";
-      };
+      package = mkPackageOption pkgs [ "gnome" "gvfs" ] { };
 
     };
 
diff --git a/nixos/modules/services/desktops/pipewire/pipewire.nix b/nixos/modules/services/desktops/pipewire/pipewire.nix
index 07ca2727cf48..04ac415c177c 100644
--- a/nixos/modules/services/desktops/pipewire/pipewire.nix
+++ b/nixos/modules/services/desktops/pipewire/pipewire.nix
@@ -25,14 +25,7 @@ in {
     services.pipewire = {
       enable = mkEnableOption (lib.mdDoc "pipewire service");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.pipewire;
-        defaultText = literalExpression "pkgs.pipewire";
-        description = lib.mdDoc ''
-          The pipewire derivation to use.
-        '';
-      };
+      package = mkPackageOption pkgs "pipewire" { };
 
       socketActivation = mkOption {
         default = true;
diff --git a/nixos/modules/services/development/athens.md b/nixos/modules/services/development/athens.md
new file mode 100644
index 000000000000..77663db509d5
--- /dev/null
+++ b/nixos/modules/services/development/athens.md
@@ -0,0 +1,52 @@
+# Athens {#module-athens}
+
+*Source:* {file}`modules/services/development/athens.nix`
+
+*Upstream documentation:* <https://docs.gomods.io/>
+
+[Athens](https://github.com/gomods/athens)
+is a Go module datastore and proxy
+
+The main goal of Athens is providing a Go proxy (`$GOPROXY`) in regions without access to `https://proxy.golang.org` or to
+improve the speed of Go module downloads for CI/CD systems.
+
+## Configuring {#module-services-development-athens-configuring}
+
+A complete list of options for the Athens module may be found
+[here](#opt-services.athens.enable).
+
+## Basic usage for a caching proxy configuration {#opt-services-development-athens-caching-proxy}
+
+A very basic configuration for Athens that acts as a caching and forwarding HTTP proxy is:
+```
+{
+    services.athens = {
+      enable = true;
+    };
+}
+```
+
+If you want to prevent Athens from writing to disk, you can instead configure it to cache modules only in memory:
+
+```
+{
+    services.athens = {
+      enable = true;
+      storageType = "memory";
+    };
+}
+```
+
+To use the local proxy in Go builds, you can set the proxy as environment variable:
+
+```
+{
+  environment.variables = {
+    GOPROXY = "http://localhost:3000"
+  };
+}
+```
+
+It is currently not possible to use the local proxy for builds done by the Nix daemon. This might be enabled
+by experimental features, specifically [`configurable-impure-env`](https://nixos.org/manual/nix/unstable/contributing/experimental-features#xp-feature-configurable-impure-env),
+in upcoming Nix versions.
diff --git a/nixos/modules/services/development/athens.nix b/nixos/modules/services/development/athens.nix
new file mode 100644
index 000000000000..34f8964a3bd5
--- /dev/null
+++ b/nixos/modules/services/development/athens.nix
@@ -0,0 +1,936 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.athens;
+
+  athensConfig = flip recursiveUpdate cfg.extraConfig (
+    {
+      GoBinary = "${cfg.goBinary}/bin/go";
+      GoEnv = cfg.goEnv;
+      GoBinaryEnvVars = lib.mapAttrsToList (k: v: "${k}=${v}") cfg.goBinaryEnvVars;
+      GoGetWorkers = cfg.goGetWorkers;
+      GoGetDir = cfg.goGetDir;
+      ProtocolWorkers = cfg.protocolWorkers;
+      LogLevel = cfg.logLevel;
+      CloudRuntime = cfg.cloudRuntime;
+      EnablePprof = cfg.enablePprof;
+      PprofPort = ":${toString cfg.pprofPort}";
+      FilterFile = cfg.filterFile;
+      RobotsFile = cfg.robotsFile;
+      Timeout = cfg.timeout;
+      StorageType = cfg.storageType;
+      TLSCertFile = cfg.tlsCertFile;
+      TLSKeyFile = cfg.tlsKeyFile;
+      Port = ":${toString cfg.port}";
+      UnixSocket = cfg.unixSocket;
+      GlobalEndpoint = cfg.globalEndpoint;
+      BasicAuthUser = cfg.basicAuthUser;
+      BasicAuthPass = cfg.basicAuthPass;
+      ForceSSL = cfg.forceSSL;
+      ValidatorHook = cfg.validatorHook;
+      PathPrefix = cfg.pathPrefix;
+      NETRCPath = cfg.netrcPath;
+      GithubToken = cfg.githubToken;
+      HGRCPath = cfg.hgrcPath;
+      TraceExporter = cfg.traceExporter;
+      StatsExporter = cfg.statsExporter;
+      SumDBs = cfg.sumDBs;
+      NoSumPatterns = cfg.noSumPatterns;
+      DownloadMode = cfg.downloadMode;
+      NetworkMode = cfg.networkMode;
+      DownloadURL = cfg.downloadURL;
+      SingleFlightType = cfg.singleFlightType;
+      IndexType = cfg.indexType;
+      ShutdownTimeout = cfg.shutdownTimeout;
+      SingleFlight = {
+        Etcd = {
+          Endpoints = builtins.concatStringsSep "," cfg.singleFlight.etcd.endpoints;
+        };
+        Redis = {
+          Endpoint = cfg.singleFlight.redis.endpoint;
+          Password = cfg.singleFlight.redis.password;
+          LockConfig = {
+            TTL = cfg.singleFlight.redis.lockConfig.ttl;
+            Timeout = cfg.singleFlight.redis.lockConfig.timeout;
+            MaxRetries = cfg.singleFlight.redis.lockConfig.maxRetries;
+          };
+        };
+        RedisSentinel = {
+          Endpoints = cfg.singleFlight.redisSentinel.endpoints;
+          MasterName = cfg.singleFlight.redisSentinel.masterName;
+          SentinelPassword = cfg.singleFlight.redisSentinel.sentinelPassword;
+          LockConfig = {
+            TTL = cfg.singleFlight.redisSentinel.lockConfig.ttl;
+            Timeout = cfg.singleFlight.redisSentinel.lockConfig.timeout;
+            MaxRetries = cfg.singleFlight.redisSentinel.lockConfig.maxRetries;
+          };
+        };
+      };
+      Storage = {
+        CDN = {
+          Endpoint = cfg.storage.cdn.endpoint;
+        };
+        Disk = {
+          RootPath = cfg.storage.disk.rootPath;
+        };
+        GCP = {
+          ProjectID = cfg.storage.gcp.projectID;
+          Bucket = cfg.storage.gcp.bucket;
+          JSONKey = cfg.storage.gcp.jsonKey;
+        };
+        Minio = {
+          Endpoint = cfg.storage.minio.endpoint;
+          Key = cfg.storage.minio.key;
+          Secret = cfg.storage.minio.secret;
+          EnableSSL = cfg.storage.minio.enableSSL;
+          Bucket = cfg.storage.minio.bucket;
+          region = cfg.storage.minio.region;
+        };
+        Mongo = {
+          URL = cfg.storage.mongo.url;
+          DefaultDBName = cfg.storage.mongo.defaultDBName;
+          CertPath = cfg.storage.mongo.certPath;
+          Insecure = cfg.storage.mongo.insecure;
+        };
+        S3 = {
+          Region = cfg.storage.s3.region;
+          Key = cfg.storage.s3.key;
+          Secret = cfg.storage.s3.secret;
+          Token = cfg.storage.s3.token;
+          Bucket = cfg.storage.s3.bucket;
+          ForcePathStyle = cfg.storage.s3.forcePathStyle;
+          UseDefaultConfiguration = cfg.storage.s3.useDefaultConfiguration;
+          CredentialsEndpoint = cfg.storage.s3.credentialsEndpoint;
+          AwsContainerCredentialsRelativeURI = cfg.storage.s3.awsContainerCredentialsRelativeURI;
+          Endpoint = cfg.storage.s3.endpoint;
+        };
+        AzureBlob = {
+          AccountName = cfg.storage.azureblob.accountName;
+          AccountKey = cfg.storage.azureblob.accountKey;
+          ContainerName = cfg.storage.azureblob.containerName;
+        };
+        External = {
+          URL = cfg.storage.external.url;
+        };
+      };
+      Index = {
+        MySQL = {
+          Protocol = cfg.index.mysql.protocol;
+          Host = cfg.index.mysql.host;
+          Port = cfg.index.mysql.port;
+          User = cfg.index.mysql.user;
+          Password = cfg.index.mysql.password;
+          Database = cfg.index.mysql.database;
+          Params = {
+            parseTime = cfg.index.mysql.params.parseTime;
+            timeout = cfg.index.mysql.params.timeout;
+          };
+        };
+        Postgres = {
+          Host = cfg.index.postgres.host;
+          Port = cfg.index.postgres.port;
+          User = cfg.index.postgres.user;
+          Password = cfg.index.postgres.password;
+          Database = cfg.index.postgres.database;
+          Params = {
+            connect_timeout = cfg.index.postgres.params.connect_timeout;
+            sslmode = cfg.index.postgres.params.sslmode;
+          };
+        };
+      };
+    }
+  );
+
+  configFile = pkgs.runCommandLocal "config.toml" { } ''
+    ${pkgs.buildPackages.jq}/bin/jq 'del(..|nulls)' \
+      < ${pkgs.writeText "config.json" (builtins.toJSON athensConfig)} | \
+    ${pkgs.buildPackages.remarshal}/bin/remarshal -if json -of toml \
+      > $out
+  '';
+in
+{
+  meta = {
+    maintainers = pkgs.athens.meta.maintainers;
+    doc = ./athens.md;
+  };
+
+  options.services.athens = {
+    enable = mkEnableOption (lib.mdDoc "Go module datastore and proxy");
+
+    package = mkOption {
+      default = pkgs.athens;
+      defaultText = literalExpression "pkgs.athens";
+      example = "pkgs.athens";
+      description = lib.mdDoc "Which athens derivation to use";
+      type = types.package;
+    };
+
+    goBinary = mkOption {
+      type = types.package;
+      default = pkgs.go;
+      defaultText = literalExpression "pkgs.go";
+      example = "pkgs.go_1_21";
+      description = lib.mdDoc ''
+        The Go package used by Athens at runtime.
+
+        Athens primarily runs two Go commands:
+        1. `go mod download -json <module>@<version>`
+        2. `go list -m -json <module>@latest`
+      '';
+    };
+
+    goEnv = mkOption {
+      type = types.enum [ "development" "production" ];
+      description = lib.mdDoc "Specifies the type of environment to run. One of 'development' or 'production'.";
+      default = "development";
+      example = "production";
+    };
+
+    goBinaryEnvVars = mkOption {
+      type = types.attrs;
+      description = lib.mdDoc "Environment variables to pass to the Go binary.";
+      example = ''
+        { "GOPROXY" = "direct", "GODEBUG" = "true" }
+      '';
+      default = { };
+    };
+
+    goGetWorkers = mkOption {
+      type = types.int;
+      description = lib.mdDoc "Number of workers concurrently downloading modules.";
+      default = 10;
+      example = 32;
+    };
+
+    goGetDir = mkOption {
+      type = types.nullOr types.path;
+      description = lib.mdDoc ''
+        Temporary directory that Athens will use to
+        fetch modules from VCS prior to persisting
+        them to a storage backend.
+
+        If the value is empty, Athens will use the
+        default OS temp directory.
+      '';
+      default = null;
+      example = "/tmp/athens";
+    };
+
+    protocolWorkers = mkOption {
+      type = types.int;
+      description = lib.mdDoc "Number of workers concurrently serving protocol paths.";
+      default = 30;
+    };
+
+    logLevel = mkOption {
+      type = types.nullOr (types.enum [ "panic" "fatal" "error" "warning" "info" "debug" "trace" ]);
+      description = lib.mdDoc ''
+        Log level for Athens.
+        Supports all logrus log levels (https://github.com/Sirupsen/logrus#level-logging)".
+      '';
+      default = "warning";
+      example = "debug";
+    };
+
+    cloudRuntime = mkOption {
+      type = types.enum [ "GCP" "none" ];
+      description = lib.mdDoc ''
+        Specifies the Cloud Provider on which the Proxy/registry is running.
+      '';
+      default = "none";
+      example = "GCP";
+    };
+
+    enablePprof = mkOption {
+      type = types.bool;
+      description = lib.mdDoc "Enable pprof endpoints.";
+      default = false;
+    };
+
+    pprofPort = mkOption {
+      type = types.port;
+      description = lib.mdDoc "Port number for pprof endpoints.";
+      default = 3301;
+      example = 443;
+    };
+
+    filterFile = mkOption {
+      type = types.nullOr types.path;
+      description = lib.mdDoc ''Filename for the include exclude filter.'';
+      default = null;
+      example = literalExpression ''
+        pkgs.writeText "filterFile" '''
+          - github.com/azure
+          + github.com/azure/azure-sdk-for-go
+          D golang.org/x/tools
+        '''
+      '';
+    };
+
+    robotsFile = mkOption {
+      type = types.nullOr types.path;
+      description = lib.mdDoc ''Provides /robots.txt for net crawlers.'';
+      default = null;
+      example = literalExpression ''pkgs.writeText "robots.txt" "# my custom robots.txt ..."'';
+    };
+
+    timeout = mkOption {
+      type = types.int;
+      description = lib.mdDoc "Timeout for external network calls in seconds.";
+      default = 300;
+      example = 3;
+    };
+
+    storageType = mkOption {
+      type = types.enum [ "memory" "disk" "mongo" "gcp" "minio" "s3" "azureblob" "external" ];
+      description = lib.mdDoc "Specifies the type of storage backend to use.";
+      default = "disk";
+    };
+
+    tlsCertFile = mkOption {
+      type = types.nullOr types.path;
+      description = lib.mdDoc "Path to the TLS certificate file.";
+      default = null;
+      example = "/etc/ssl/certs/athens.crt";
+    };
+
+    tlsKeyFile = mkOption {
+      type = types.nullOr types.path;
+      description = lib.mdDoc "Path to the TLS key file.";
+      default = null;
+      example = "/etc/ssl/certs/athens.key";
+    };
+
+    port = mkOption {
+      type = types.port;
+      default = 3000;
+      description = lib.mdDoc ''
+        Port number Athens listens on.
+      '';
+      example = 443;
+    };
+
+    unixSocket = mkOption {
+      type = types.nullOr types.path;
+      description = lib.mdDoc ''
+        Path to the unix socket file.
+        If set, Athens will listen on the unix socket instead of TCP socket.
+      '';
+      default = null;
+      example = "/run/athens.sock";
+    };
+
+    globalEndpoint = mkOption {
+      type = types.str;
+      description = lib.mdDoc ''
+        Endpoint for a package registry in case of a proxy cache miss.
+      '';
+      default = "";
+      example = "http://upstream-athens.example.com:3000";
+    };
+
+    basicAuthUser = mkOption {
+      type = types.nullOr types.str;
+      description = lib.mdDoc ''
+        Username for basic auth.
+      '';
+      default = null;
+      example = "user";
+    };
+
+    basicAuthPass = mkOption {
+      type = types.nullOr types.str;
+      description = lib.mdDoc ''
+        Password for basic auth. Warning: this is stored in plain text in the config file.
+      '';
+      default = null;
+      example = "swordfish";
+    };
+
+    forceSSL = mkOption {
+      type = types.bool;
+      description = lib.mdDoc ''
+        Force SSL redirects for incoming requests.
+      '';
+      default = false;
+    };
+
+    validatorHook = mkOption {
+      type = types.nullOr types.str;
+      description = lib.mdDoc ''
+        Endpoint to validate modules against.
+
+        Not used if empty.
+      '';
+      default = null;
+      example = "https://validation.example.com";
+    };
+
+    pathPrefix = mkOption {
+      type = types.nullOr types.str;
+      description = lib.mdDoc ''
+        Sets basepath for all routes.
+      '';
+      default = null;
+      example = "/athens";
+    };
+
+    netrcPath = mkOption {
+      type = types.nullOr types.path;
+      description = lib.mdDoc ''
+        Path to the .netrc file.
+      '';
+      default = null;
+      example = "/home/user/.netrc";
+    };
+
+    githubToken = mkOption {
+      type = types.nullOr types.str;
+      description = lib.mdDoc ''
+        Creates .netrc file with the given token to be used for GitHub.
+        Warning: this is stored in plain text in the config file.
+      '';
+      default = null;
+      example = "ghp_1234567890";
+    };
+
+    hgrcPath = mkOption {
+      type = types.nullOr types.path;
+      description = lib.mdDoc ''
+        Path to the .hgrc file.
+      '';
+      default = null;
+      example = "/home/user/.hgrc";
+    };
+
+    traceExporter = mkOption {
+      type = types.nullOr (types.enum [ "jaeger" "datadog" ]);
+      description = lib.mdDoc ''
+        Trace exporter to use.
+      '';
+      default = null;
+    };
+
+    traceExporterURL = mkOption {
+      type = types.nullOr types.str;
+      description = lib.mdDoc ''
+        URL endpoint that traces will be sent to.
+      '';
+      default = null;
+      example = "http://localhost:14268";
+    };
+
+    statsExporter = mkOption {
+      type = types.nullOr (types.enum [ "prometheus" ]);
+      description = lib.mdDoc "Stats exporter to use.";
+      default = null;
+    };
+
+    sumDBs = mkOption {
+      type = types.listOf types.str;
+      description = lib.mdDoc ''
+        List of fully qualified URLs that Athens will proxy
+        that the go command can use a checksum verifier.
+      '';
+      default = [ "https://sum.golang.org" ];
+    };
+
+    noSumPatterns = mkOption {
+      type = types.listOf types.str;
+      description = lib.mdDoc ''
+        List of patterns that Athens sum db proxy will return a 403 for.
+      '';
+      default = [ ];
+      example = [ "github.com/mycompany/*" ];
+    };
+
+    downloadMode = mkOption {
+      type = types.oneOf [ (types.enum [ "sync" "async" "redirect" "async_redirect" "none" ]) (types.strMatching "^file:.*$|^custom:.*$") ];
+      description = lib.mdDoc ''
+        Defines how Athens behaves when a module@version
+        is not found in storage. There are 7 options:
+        1. "sync": download the module synchronously and
+        return the results to the client.
+        2. "async": return 404, but asynchronously store the module
+        in the storage backend.
+        3. "redirect": return a 301 redirect status to the client
+        with the base URL as the DownloadRedirectURL from below.
+        4. "async_redirect": same as option number 3 but it will
+        asynchronously store the module to the backend.
+        5. "none": return 404 if a module is not found and do nothing.
+        6. "file:<path>": will point to an HCL file that specifies
+        any of the 5 options above based on different import paths.
+        7. "custom:<base64-encoded-hcl>" is the same as option 6
+        but the file is fully encoded in the option. This is
+        useful for using an environment variable in serverless
+        deployments.
+      '';
+      default = "async_redirect";
+    };
+
+    networkMode = mkOption {
+      type = types.enum [ "strict" "offline" "fallback" ];
+      description = lib.mdDoc ''
+        Configures how Athens will return the results
+        of the /list endpoint as it can be assembled from both its own
+        storage and the upstream VCS.
+
+        Note, that for better error messaging, this would also affect how other
+        endpoints behave.
+
+        Modes:
+        1. strict: merge VCS versions with storage versions, but fail if either of them fails.
+        2. offline: only get storage versions, never reach out to VCS.
+        3. fallback: only return storage versions, if VCS fails. Note this means that you may
+        see inconsistent results since fallback mode does a best effort of giving you what's
+        available at the time of requesting versions.
+      '';
+      default = "strict";
+    };
+
+    downloadURL = mkOption {
+      type = types.str;
+      description = lib.mdDoc "URL used if DownloadMode is set to redirect.";
+      default = "https://proxy.golang.org";
+    };
+
+    singleFlightType = mkOption {
+      type = types.enum [ "memory" "etcd" "redis" "redis-sentinel" "gcp" "azureblob" ];
+      description = lib.mdDoc ''
+        Determines what mechanism Athens uses to manage concurrency flowing into the Athens backend.
+      '';
+      default = "memory";
+    };
+
+    indexType = mkOption {
+      type = types.enum [ "none" "memory" "mysql" "postgres" ];
+      description = lib.mdDoc ''
+        Type of index backend Athens will use.
+      '';
+      default = "none";
+    };
+
+    shutdownTimeout = mkOption {
+      type = types.int;
+      description = lib.mdDoc ''
+        Number of seconds to wait for the server to shutdown gracefully.
+      '';
+      default = 60;
+      example = 1;
+    };
+
+    singleFlight = {
+      etcd = {
+        endpoints = mkOption {
+          type = types.listOf types.str;
+          description = lib.mdDoc "URLs that determine all distributed etcd servers.";
+          default = [ ];
+          example = [ "localhost:2379" ];
+        };
+      };
+      redis = {
+        endpoint = mkOption {
+          type = types.str;
+          description = lib.mdDoc "URL of the redis server.";
+          default = "";
+          example = "localhost:6379";
+        };
+        password = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Password for the redis server. Warning: this is stored in plain text in the config file.";
+          default = "";
+          example = "swordfish";
+        };
+
+        lockConfig = {
+          ttl = mkOption {
+            type = types.int;
+            description = lib.mdDoc "TTL for the lock in seconds.";
+            default = 900;
+            example = 1;
+          };
+          timeout = mkOption {
+            type = types.int;
+            description = lib.mdDoc "Timeout for the lock in seconds.";
+            default = 15;
+            example = 1;
+          };
+          maxRetries = mkOption {
+            type = types.int;
+            description = lib.mdDoc "Maximum number of retries for the lock.";
+            default = 10;
+            example = 1;
+          };
+        };
+      };
+
+      redisSentinel = {
+        endpoints = mkOption {
+          type = types.listOf types.str;
+          description = lib.mdDoc "URLs that determine all distributed redis servers.";
+          default = [ ];
+          example = [ "localhost:26379" ];
+        };
+        masterName = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Name of the sentinel master server.";
+          default = "";
+          example = "redis-1";
+        };
+        sentinelPassword = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Password for the sentinel server. Warning: this is stored in plain text in the config file.";
+          default = "";
+          example = "swordfish";
+        };
+
+        lockConfig = {
+          ttl = mkOption {
+            type = types.int;
+            description = lib.mdDoc "TTL for the lock in seconds.";
+            default = 900;
+            example = 1;
+          };
+          timeout = mkOption {
+            type = types.int;
+            description = lib.mdDoc "Timeout for the lock in seconds.";
+            default = 15;
+            example = 1;
+          };
+          maxRetries = mkOption {
+            type = types.int;
+            description = lib.mdDoc "Maximum number of retries for the lock.";
+            default = 10;
+            example = 1;
+          };
+        };
+      };
+    };
+
+    storage = {
+      cdn = {
+        endpoint = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "hostname of the CDN server.";
+          example = "cdn.example.com";
+          default = null;
+        };
+      };
+
+      disk = {
+        rootPath = mkOption {
+          type = types.nullOr types.path;
+          description = lib.mdDoc "Athens disk root folder.";
+          default = "/var/lib/athens";
+        };
+      };
+
+      gcp = {
+        projectID = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "GCP project ID.";
+          example = "my-project";
+          default = null;
+        };
+        bucket = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "GCP backend storage bucket.";
+          example = "my-bucket";
+          default = null;
+        };
+        jsonKey = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Base64 encoded GCP service account key. Warning: this is stored in plain text in the config file.";
+          default = null;
+        };
+      };
+
+      minio = {
+        endpoint = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Endpoint of the minio storage backend.";
+          example = "minio.example.com:9001";
+          default = null;
+        };
+        key = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Access key id for the minio storage backend.";
+          example = "minio";
+          default = null;
+        };
+        secret = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Secret key for the minio storage backend. Warning: this is stored in plain text in the config file.";
+          example = "minio123";
+          default = null;
+        };
+        enableSSL = mkOption {
+          type = types.bool;
+          description = lib.mdDoc "Enable SSL for the minio storage backend.";
+          default = false;
+        };
+        bucket = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Bucket name for the minio storage backend.";
+          example = "gomods";
+          default = null;
+        };
+        region = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Region for the minio storage backend.";
+          example = "us-east-1";
+          default = null;
+        };
+      };
+
+      mongo = {
+        url = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "URL of the mongo database.";
+          example = "mongodb://localhost:27017";
+          default = null;
+        };
+        defaultDBName = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Name of the mongo database.";
+          example = "athens";
+          default = null;
+        };
+        certPath = mkOption {
+          type = types.nullOr types.path;
+          description = lib.mdDoc "Path to the certificate file for the mongo database.";
+          example = "/etc/ssl/mongo.pem";
+          default = null;
+        };
+        insecure = mkOption {
+          type = types.bool;
+          description = lib.mdDoc "Allow insecure connections to the mongo database.";
+          default = false;
+        };
+      };
+
+      s3 = {
+        region = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Region of the S3 storage backend.";
+          example = "eu-west-3";
+          default = null;
+        };
+        key = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Access key id for the S3 storage backend.";
+          example = "minio";
+          default = null;
+        };
+        secret = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Secret key for the S3 storage backend. Warning: this is stored in plain text in the config file.";
+          default = "";
+        };
+        token = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Token for the S3 storage backend. Warning: this is stored in plain text in the config file.";
+          default = null;
+        };
+        bucket = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Bucket name for the S3 storage backend.";
+          example = "gomods";
+          default = null;
+        };
+        forcePathStyle = mkOption {
+          type = types.bool;
+          description = lib.mdDoc "Force path style for the S3 storage backend.";
+          default = false;
+        };
+        useDefaultConfiguration = mkOption {
+          type = types.bool;
+          description = lib.mdDoc "Use default configuration for the S3 storage backend.";
+          default = false;
+        };
+        credentialsEndpoint = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Credentials endpoint for the S3 storage backend.";
+          default = "";
+        };
+        awsContainerCredentialsRelativeURI = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Container relative url (used by fargate).";
+          default = null;
+        };
+        endpoint = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Endpoint for the S3 storage backend.";
+          default = null;
+        };
+      };
+
+      azureblob = {
+        accountName = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Account name for the Azure Blob storage backend.";
+          default = null;
+        };
+        accountKey = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Account key for the Azure Blob storage backend. Warning: this is stored in plain text in the config file.";
+          default = null;
+        };
+        containerName = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Container name for the Azure Blob storage backend.";
+          default = null;
+        };
+      };
+
+      external = {
+        url = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "URL of the backend storage layer.";
+          example = "https://athens.example.com";
+          default = null;
+        };
+      };
+    };
+
+    index = {
+      mysql = {
+        protocol = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Protocol for the MySQL database.";
+          default = "tcp";
+        };
+        host = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Host for the MySQL database.";
+          default = "localhost";
+        };
+        port = mkOption {
+          type = types.int;
+          description = lib.mdDoc "Port for the MySQL database.";
+          default = 3306;
+        };
+        user = mkOption {
+          type = types.str;
+          description = lib.mdDoc "User for the MySQL database.";
+          default = "root";
+        };
+        password = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Password for the MySQL database. Warning: this is stored in plain text in the config file.";
+          default = null;
+        };
+        database = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Database name for the MySQL database.";
+          default = "athens";
+        };
+        params = {
+          parseTime = mkOption {
+            type = types.nullOr types.str;
+            description = lib.mdDoc "Parse time for the MySQL database.";
+            default = "true";
+          };
+          timeout = mkOption {
+            type = types.nullOr types.str;
+            description = lib.mdDoc "Timeout for the MySQL database.";
+            default = "30s";
+          };
+        };
+      };
+
+      postgres = {
+        host = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Host for the Postgres database.";
+          default = "localhost";
+        };
+        port = mkOption {
+          type = types.int;
+          description = lib.mdDoc "Port for the Postgres database.";
+          default = 5432;
+        };
+        user = mkOption {
+          type = types.str;
+          description = lib.mdDoc "User for the Postgres database.";
+          default = "postgres";
+        };
+        password = mkOption {
+          type = types.nullOr types.str;
+          description = lib.mdDoc "Password for the Postgres database. Warning: this is stored in plain text in the config file.";
+          default = null;
+        };
+        database = mkOption {
+          type = types.str;
+          description = lib.mdDoc "Database name for the Postgres database.";
+          default = "athens";
+        };
+        params = {
+          connect_timeout = mkOption {
+            type = types.nullOr types.str;
+            description = lib.mdDoc "Connect timeout for the Postgres database.";
+            default = "30s";
+          };
+          sslmode = mkOption {
+            type = types.nullOr types.str;
+            description = lib.mdDoc "SSL mode for the Postgres database.";
+            default = "disable";
+          };
+        };
+      };
+    };
+
+    extraConfig = mkOption {
+      type = types.attrs;
+      description = lib.mdDoc ''
+        Extra configuration options for the athens config file.
+      '';
+      default = { };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.athens = {
+      description = "Athens Go module proxy";
+      documentation = [ "https://docs.gomods.io" ];
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-online.target" ];
+      wants = [ "network-online.target" ];
+
+      serviceConfig = {
+        Restart = "on-abnormal";
+        Nice = 5;
+        ExecStart = ''${cfg.package}/bin/athens -config_file=${configFile}'';
+
+        KillMode = "mixed";
+        KillSignal = "SIGINT";
+        TimeoutStopSec = cfg.shutdownTimeout;
+
+        LimitNOFILE = 1048576;
+        LimitNPROC = 512;
+
+        DynamicUser = true;
+        PrivateTmp = true;
+        PrivateDevices = true;
+        ProtectHome = "read-only";
+        ProtectSystem = "full";
+
+        ReadWritePaths = mkIf (cfg.storage.disk.rootPath != null && (! hasPrefix "/var/lib/" cfg.storage.disk.rootPath)) [ cfg.storage.disk.rootPath ];
+        StateDirectory = mkIf (hasPrefix "/var/lib/" cfg.storage.disk.rootPath) [ (removePrefix "/var/lib/" cfg.storage.disk.rootPath) ];
+
+        CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
+        AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
+        NoNewPrivileges = true;
+      };
+    };
+
+    networking.firewall = {
+      allowedTCPPorts = optionals (cfg.unixSocket == null) [ cfg.port ]
+        ++ optionals cfg.enablePprof [ cfg.pprofPort ];
+    };
+  };
+
+}
diff --git a/nixos/modules/services/development/distccd.nix b/nixos/modules/services/development/distccd.nix
index a3c909eb1959..c33bf436bffb 100644
--- a/nixos/modules/services/development/distccd.nix
+++ b/nixos/modules/services/development/distccd.nix
@@ -66,14 +66,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.distcc;
-        defaultText = literalExpression "pkgs.distcc";
-        description = lib.mdDoc ''
-          The distcc package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "distcc" { };
 
       port = mkOption {
         type = types.port;
diff --git a/nixos/modules/services/development/jupyter/default.nix b/nixos/modules/services/development/jupyter/default.nix
index 9f7910844468..da8c7547fdd7 100644
--- a/nixos/modules/services/development/jupyter/default.nix
+++ b/nixos/modules/services/development/jupyter/default.nix
@@ -34,17 +34,10 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      # NOTE: We don't use top-level jupyter because we don't
-      # want to pass in JUPYTER_PATH but use .environment instead,
-      # saving a rebuild.
-      default = pkgs.python3.pkgs.notebook;
-      defaultText = literalExpression "pkgs.python3.pkgs.notebook";
-      description = lib.mdDoc ''
-        Jupyter package to use.
-      '';
-    };
+    # NOTE: We don't use top-level jupyter because we don't
+    # want to pass in JUPYTER_PATH but use .environment instead,
+    # saving a rebuild.
+    package = mkPackageOption pkgs [ "python3" "pkgs" "notebook" ] { };
 
     command = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/development/rstudio-server/default.nix b/nixos/modules/services/development/rstudio-server/default.nix
index bf4c7727bf74..fc3756edf0ab 100644
--- a/nixos/modules/services/development/rstudio-server/default.nix
+++ b/nixos/modules/services/development/rstudio-server/default.nix
@@ -39,14 +39,8 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.rstudio-server;
-      defaultText = literalExpression "pkgs.rstudio-server";
-      example = literalExpression "pkgs.rstudioServerWrapper.override { packages = [ pkgs.rPackages.ggplot2 ]; }";
-      description = lib.mdDoc ''
-        Rstudio server package to use. Can be set to rstudioServerWrapper to provide packages.
-      '';
+    package = mkPackageOption pkgs "rstudio-server" {
+      example = "rstudioServerWrapper.override { packages = [ pkgs.rPackages.ggplot2 ]; }";
     };
 
     rserverExtraConfig = mkOption {
diff --git a/nixos/modules/services/development/zammad.nix b/nixos/modules/services/development/zammad.nix
index d24ed24ef395..87aceddd6635 100644
--- a/nixos/modules/services/development/zammad.nix
+++ b/nixos/modules/services/development/zammad.nix
@@ -30,12 +30,7 @@ in
     services.zammad = {
       enable = mkEnableOption (lib.mdDoc "Zammad, a web-based, open source user support/ticketing solution");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.zammad;
-        defaultText = literalExpression "pkgs.zammad";
-        description = lib.mdDoc "Zammad package to use.";
-      };
+      package = mkPackageOption pkgs "zammad" { };
 
       dataDir = mkOption {
         type = types.path;
diff --git a/nixos/modules/services/display-managers/greetd.nix b/nixos/modules/services/display-managers/greetd.nix
index 89cb81f3a78f..779e141ca24b 100644
--- a/nixos/modules/services/display-managers/greetd.nix
+++ b/nixos/modules/services/display-managers/greetd.nix
@@ -10,12 +10,7 @@ in
   options.services.greetd = {
     enable = mkEnableOption (lib.mdDoc "greetd");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.greetd.greetd;
-      defaultText = literalExpression "pkgs.greetd.greetd";
-      description = lib.mdDoc "The greetd package that should be used.";
-    };
+    package = mkPackageOption pkgs [ "greetd" "greetd" ] { };
 
     settings = mkOption {
       type = settingsFormat.type;
diff --git a/nixos/modules/services/editors/emacs.nix b/nixos/modules/services/editors/emacs.nix
index fad4f39ff210..6f45be6640bc 100644
--- a/nixos/modules/services/editors/emacs.nix
+++ b/nixos/modules/services/editors/emacs.nix
@@ -63,14 +63,7 @@ in
     };
 
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.emacs;
-      defaultText = literalExpression "pkgs.emacs";
-      description = lib.mdDoc ''
-        emacs derivation to use.
-      '';
-    };
+    package = mkPackageOption pkgs "emacs" { };
 
     defaultEditor = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/editors/infinoted.nix b/nixos/modules/services/editors/infinoted.nix
index de0989994019..976163d4d0b2 100644
--- a/nixos/modules/services/editors/infinoted.nix
+++ b/nixos/modules/services/editors/infinoted.nix
@@ -8,14 +8,7 @@ in {
   options.services.infinoted = {
     enable = mkEnableOption (lib.mdDoc "infinoted");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.libinfinity;
-      defaultText = literalExpression "pkgs.libinfinity";
-      description = lib.mdDoc ''
-        Package providing infinoted
-      '';
-    };
+    package = mkPackageOption pkgs "libinfinity" { };
 
     keyFile = mkOption {
       type = types.nullOr types.path;
diff --git a/nixos/modules/services/finance/odoo.nix b/nixos/modules/services/finance/odoo.nix
index b8574ed09af9..aa9bd0014d98 100644
--- a/nixos/modules/services/finance/odoo.nix
+++ b/nixos/modules/services/finance/odoo.nix
@@ -11,12 +11,7 @@ in
     services.odoo = {
       enable = mkEnableOption (lib.mdDoc "odoo");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.odoo;
-        defaultText = literalExpression "pkgs.odoo";
-        description = lib.mdDoc "Odoo package to use.";
-      };
+      package = mkPackageOption pkgs "odoo" { };
 
       addons = mkOption {
         type = with types; listOf package;
diff --git a/nixos/modules/services/games/asf.nix b/nixos/modules/services/games/asf.nix
index 432de6336ce2..27d174d6726b 100644
--- a/nixos/modules/services/games/asf.nix
+++ b/nixos/modules/services/games/asf.nix
@@ -47,12 +47,12 @@ in
             description = lib.mdDoc "Whether to start the web-ui. This is the preferred way of configuring things such as the steam guard token.";
           };
 
-          package = mkOption {
-            type = types.package;
-            default = pkgs.ArchiSteamFarm.ui;
-            defaultText = lib.literalExpression "pkgs.ArchiSteamFarm.ui";
-            description =
-              lib.mdDoc "Web-UI package to use. Contents must be in lib/dist.";
+          package = mkPackageOption pkgs [ "ArchiSteamFarm" "ui" ] {
+            extraDescription = ''
+              ::: {.note}
+              Contents must be in lib/dist
+              :::
+            '';
           };
         };
       };
@@ -65,12 +65,13 @@ in
       description = lib.mdDoc "The Web-UI hosted on 127.0.0.1:1242.";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.ArchiSteamFarm;
-      defaultText = lib.literalExpression "pkgs.ArchiSteamFarm";
-      description =
-        lib.mdDoc "Package to use. Should always be the latest version, for security reasons, since this module uses very new features and to not get out of sync with the Steam API.";
+    package = mkPackageOption pkgs "ArchiSteamFarm" {
+      extraDescription = ''
+        ::: {.warning}
+        Should always be the latest version, for security reasons,
+        since this module uses very new features and to not get out of sync with the Steam API.
+        :::
+      '';
     };
 
     dataDir = mkOption {
diff --git a/nixos/modules/services/games/crossfire-server.nix b/nixos/modules/services/games/crossfire-server.nix
index 0849667e61c9..b19a86253cb4 100644
--- a/nixos/modules/services/games/crossfire-server.nix
+++ b/nixos/modules/services/games/crossfire-server.nix
@@ -15,13 +15,11 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.crossfire-server;
-      defaultText = literalExpression "pkgs.crossfire-server";
-      description = lib.mdDoc ''
-        The package to use for the Crossfire server (and map/arch data, if you
-        don't change dataDir).
+    package = mkPackageOption pkgs "crossfire-server" {
+      extraDescription = ''
+        ::: {.note}
+        This will also be used for map/arch data, if you don't change {option}`dataDir`
+        :::
       '';
     };
 
diff --git a/nixos/modules/services/games/deliantra-server.nix b/nixos/modules/services/games/deliantra-server.nix
index f39044eda7c7..b405f338fe3d 100644
--- a/nixos/modules/services/games/deliantra-server.nix
+++ b/nixos/modules/services/games/deliantra-server.nix
@@ -15,13 +15,11 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.deliantra-server;
-      defaultText = literalExpression "pkgs.deliantra-server";
-      description = lib.mdDoc ''
-        The package to use for the Deliantra server (and map/arch data, if you
-        don't change dataDir).
+    package = mkPackageOption pkgs "deliantra-server" {
+      extraDescription = ''
+        ::: {.note}
+        This will also be used for map/arch data, if you don't change {option}`dataDir`
+        :::
       '';
     };
 
diff --git a/nixos/modules/services/games/factorio.nix b/nixos/modules/services/games/factorio.nix
index e6c4522d5d1d..14bb80c2d112 100644
--- a/nixos/modules/services/games/factorio.nix
+++ b/nixos/modules/services/games/factorio.nix
@@ -208,14 +208,8 @@ in
           This option is insecure. Use extraSettingsFile instead.
         '';
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.factorio-headless;
-        defaultText = literalExpression "pkgs.factorio-headless";
-        example = literalExpression "pkgs.factorio-headless-experimental";
-        description = lib.mdDoc ''
-          Factorio version to use. This defaults to the stable channel.
-        '';
+      package = mkPackageOption pkgs "factorio-headless" {
+        example = "factorio-headless-experimental";
       };
       password = mkOption {
         type = types.nullOr types.str;
diff --git a/nixos/modules/services/games/mchprs.nix b/nixos/modules/services/games/mchprs.nix
index a65001b0b3e2..71e546049c58 100644
--- a/nixos/modules/services/games/mchprs.nix
+++ b/nixos/modules/services/games/mchprs.nix
@@ -73,12 +73,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.mchprs;
-        defaultText = literalExpression "pkgs.mchprs";
-        description = mdDoc "Version of MCHPRS to run.";
-      };
+      package = mkPackageOption pkgs "mchprs" { };
 
       settings = mkOption {
         type = types.submodule {
diff --git a/nixos/modules/services/games/minecraft-server.nix b/nixos/modules/services/games/minecraft-server.nix
index 77f92ab97db7..116fc533dfd8 100644
--- a/nixos/modules/services/games/minecraft-server.nix
+++ b/nixos/modules/services/games/minecraft-server.nix
@@ -150,12 +150,8 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.minecraft-server;
-        defaultText = literalExpression "pkgs.minecraft-server";
-        example = literalExpression "pkgs.minecraft-server_1_12_2";
-        description = lib.mdDoc "Version of minecraft-server to run.";
+      package = mkPackageOption pkgs "minecraft-server" {
+        example = "minecraft-server_1_12_2";
       };
 
       jvmOpts = mkOption {
diff --git a/nixos/modules/services/hardware/bluetooth.nix b/nixos/modules/services/hardware/bluetooth.nix
index 2a58be51bb02..51ec12f96537 100644
--- a/nixos/modules/services/hardware/bluetooth.nix
+++ b/nixos/modules/services/hardware/bluetooth.nix
@@ -4,7 +4,7 @@ let
   package = cfg.package;
 
   inherit (lib)
-    mkDefault mkEnableOption mkIf mkOption
+    mkDefault mkEnableOption mkIf mkOption mkPackageOption
     mkRenamedOptionModule mkRemovedOptionModule
     concatStringsSep escapeShellArgs literalExpression
     optional optionals optionalAttrs recursiveUpdate types;
@@ -46,14 +46,7 @@ in
         description = lib.mdDoc "Whether to power up the default Bluetooth controller on boot.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.bluez;
-        defaultText = literalExpression "pkgs.bluez";
-        description = lib.mdDoc ''
-          Which BlueZ package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "bluez" { };
 
       disabledPlugins = mkOption {
         type = types.listOf types.str;
diff --git a/nixos/modules/services/hardware/freefall.nix b/nixos/modules/services/hardware/freefall.nix
index 7b794264ff35..2985739bc2df 100644
--- a/nixos/modules/services/hardware/freefall.nix
+++ b/nixos/modules/services/hardware/freefall.nix
@@ -18,14 +18,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.freefall;
-      defaultText = literalExpression "pkgs.freefall";
-      description = lib.mdDoc ''
-        freefall derivation to use.
-      '';
-    };
+    package = mkPackageOption pkgs "freefall" { };
 
     devices = mkOption {
       type = types.listOf types.str;
diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix
index 7b6c336bd221..6b3a109ed6f7 100644
--- a/nixos/modules/services/hardware/fwupd.nix
+++ b/nixos/modules/services/hardware/fwupd.nix
@@ -94,14 +94,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.fwupd;
-        defaultText = literalExpression "pkgs.fwupd";
-        description = lib.mdDoc ''
-          Which fwupd package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "fwupd" { };
 
       daemonSettings = mkOption {
         type = types.submodule {
diff --git a/nixos/modules/services/hardware/joycond.nix b/nixos/modules/services/hardware/joycond.nix
index df3239cb2a7d..060303b520e5 100644
--- a/nixos/modules/services/hardware/joycond.nix
+++ b/nixos/modules/services/hardware/joycond.nix
@@ -10,14 +10,7 @@ with lib;
   options.services.joycond = {
     enable = mkEnableOption (lib.mdDoc "support for Nintendo Pro Controllers and Joycons");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.joycond;
-      defaultText = lib.literalExpression "pkgs.joycond";
-      description = lib.mdDoc ''
-        The joycond package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "joycond" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/hardware/kanata.nix b/nixos/modules/services/hardware/kanata.nix
index aac20c6c760e..0b77bfbc33b3 100644
--- a/nixos/modules/services/hardware/kanata.nix
+++ b/nixos/modules/services/hardware/kanata.nix
@@ -146,16 +146,11 @@ in
 {
   options.services.kanata = {
     enable = mkEnableOption (mdDoc "kanata");
-    package = mkOption {
-      type = types.package;
-      default = pkgs.kanata;
-      defaultText = literalExpression "pkgs.kanata";
-      example = literalExpression "pkgs.kanata-with-cmd";
-      description = mdDoc ''
-        The kanata package to use.
-
+    package = mkPackageOption pkgs "kanata" {
+      example = "kanata-with-cmd";
+      extraDescription = ''
         ::: {.note}
-        If `danger-enable-cmd` is enabled in any of the keyboards, the
+        If {option}`danger-enable-cmd` is enabled in any of the keyboards, the
         `kanata-with-cmd` package should be used.
         :::
       '';
diff --git a/nixos/modules/services/hardware/openrgb.nix b/nixos/modules/services/hardware/openrgb.nix
index 13b1d07e53b7..81b199e50778 100644
--- a/nixos/modules/services/hardware/openrgb.nix
+++ b/nixos/modules/services/hardware/openrgb.nix
@@ -8,12 +8,7 @@ in {
   options.services.hardware.openrgb = {
     enable = mkEnableOption (lib.mdDoc "OpenRGB server");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.openrgb;
-      defaultText = literalMD "pkgs.openrgb";
-      description = lib.mdDoc "Set version of openrgb package to use.";
-    };
+    package = mkPackageOption pkgs "openrgb" { };
 
     motherboard = mkOption {
       type = types.nullOr (types.enum [ "amd" "intel" ]);
diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix
index 2cac2e8e8bb4..8408844c4f94 100644
--- a/nixos/modules/services/hardware/sane.nix
+++ b/nixos/modules/services/hardware/sane.nix
@@ -114,14 +114,11 @@ in
       '';
     };
 
-    hardware.sane.drivers.scanSnap.package = mkOption {
-      type = types.package;
-      default = pkgs.sane-drivers.epjitsu;
-      defaultText = literalExpression "pkgs.sane-drivers.epjitsu";
-      description = lib.mdDoc ''
-        Epjitsu driver package to use. Useful if you want to extract the driver files yourself.
+    hardware.sane.drivers.scanSnap.package = mkPackageOption pkgs [ "sane-drivers" "epjitsu" ] {
+      extraDescription = ''
+        Useful if you want to extract the driver files yourself.
 
-        The process is described in the `/etc/sane.d/epjitsu.conf` file in
+        The process is described in the {file}`/etc/sane.d/epjitsu.conf` file in
         the `sane-backends` package.
       '';
     };
diff --git a/nixos/modules/services/hardware/thermald.nix b/nixos/modules/services/hardware/thermald.nix
index 6b694ede5885..7ae602823cd6 100644
--- a/nixos/modules/services/hardware/thermald.nix
+++ b/nixos/modules/services/hardware/thermald.nix
@@ -25,12 +25,7 @@ in
         description = lib.mdDoc "the thermald manual configuration file.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.thermald;
-        defaultText = literalExpression "pkgs.thermald";
-        description = lib.mdDoc "Which thermald package to use.";
-      };
+      package = mkPackageOption pkgs "thermald" { };
     };
   };
 
diff --git a/nixos/modules/services/hardware/undervolt.nix b/nixos/modules/services/hardware/undervolt.nix
index 258f09bbab09..67d8171587bb 100644
--- a/nixos/modules/services/hardware/undervolt.nix
+++ b/nixos/modules/services/hardware/undervolt.nix
@@ -47,14 +47,7 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.undervolt;
-      defaultText = literalExpression "pkgs.undervolt";
-      description = lib.mdDoc ''
-        undervolt derivation to use.
-      '';
-    };
+    package = mkPackageOption pkgs "undervolt" { };
 
     coreOffset = mkOption {
       type = types.nullOr types.int;
diff --git a/nixos/modules/services/hardware/upower.nix b/nixos/modules/services/hardware/upower.nix
index aacc8a63dbeb..0ae31d99aa86 100644
--- a/nixos/modules/services/hardware/upower.nix
+++ b/nixos/modules/services/hardware/upower.nix
@@ -27,14 +27,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.upower;
-        defaultText = literalExpression "pkgs.upower";
-        description = lib.mdDoc ''
-          Which upower package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "upower" { };
 
       enableWattsUpPro = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/hardware/vdr.nix b/nixos/modules/services/hardware/vdr.nix
index de63ed893b02..afa64fa16c4a 100644
--- a/nixos/modules/services/hardware/vdr.nix
+++ b/nixos/modules/services/hardware/vdr.nix
@@ -14,12 +14,8 @@ in {
     services.vdr = {
       enable = mkEnableOption (lib.mdDoc "VDR. Please put config into ${libDir}");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.vdr;
-        defaultText = literalExpression "pkgs.vdr";
-        example = literalExpression "pkgs.wrapVdr.override { plugins = with pkgs.vdrPlugins; [ hello ]; }";
-        description = lib.mdDoc "Package to use.";
+      package = mkPackageOption pkgs "vdr" {
+        example = "wrapVdr.override { plugins = with pkgs.vdrPlugins; [ hello ]; }";
       };
 
       videoDir = mkOption {
diff --git a/nixos/modules/services/home-automation/esphome.nix b/nixos/modules/services/home-automation/esphome.nix
index 080c8876382f..4fc007a97683 100644
--- a/nixos/modules/services/home-automation/esphome.nix
+++ b/nixos/modules/services/home-automation/esphome.nix
@@ -26,12 +26,7 @@ in
   options.services.esphome = {
     enable = mkEnableOption (mdDoc "esphome");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.esphome;
-      defaultText = literalExpression "pkgs.esphome";
-      description = mdDoc "The package to use for the esphome command.";
-    };
+    package = lib.mkPackageOption pkgs "esphome" { };
 
     enableUnixSocket = mkOption {
       type = types.bool;
@@ -107,10 +102,10 @@ in
         ProtectClock = true;
         ProtectControlGroups = true;
         ProtectHome = true;
-        ProtectHostname = true;
-        ProtectKernelLogs = true;
+        ProtectHostname = false; # breaks bwrap
+        ProtectKernelLogs = false; # breaks bwrap
         ProtectKernelModules = true;
-        ProtectKernelTunables = true;
+        ProtectKernelTunables = false; # breaks bwrap
         ProtectProc = "invisible";
         ProcSubset = "all"; # Using "pid" breaks bwrap
         ProtectSystem = "strict";
diff --git a/nixos/modules/services/home-automation/zigbee2mqtt.nix b/nixos/modules/services/home-automation/zigbee2mqtt.nix
index 6b5bd8a0d9bb..a653e49a09f6 100644
--- a/nixos/modules/services/home-automation/zigbee2mqtt.nix
+++ b/nixos/modules/services/home-automation/zigbee2mqtt.nix
@@ -20,14 +20,7 @@ in
   options.services.zigbee2mqtt = {
     enable = mkEnableOption (lib.mdDoc "zigbee2mqtt service");
 
-    package = mkOption {
-      description = lib.mdDoc "Zigbee2mqtt package to use";
-      default = pkgs.zigbee2mqtt;
-      defaultText = literalExpression ''
-        pkgs.zigbee2mqtt
-      '';
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "zigbee2mqtt" { };
 
     dataDir = mkOption {
       description = lib.mdDoc "Zigbee2mqtt data directory";
diff --git a/nixos/modules/services/logging/SystemdJournal2Gelf.nix b/nixos/modules/services/logging/SystemdJournal2Gelf.nix
index 3d85c2b62c63..429dde33b521 100644
--- a/nixos/modules/services/logging/SystemdJournal2Gelf.nix
+++ b/nixos/modules/services/logging/SystemdJournal2Gelf.nix
@@ -33,14 +33,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.systemd-journal2gelf;
-        defaultText = literalExpression "pkgs.systemd-journal2gelf";
-        description = lib.mdDoc ''
-          SystemdJournal2Gelf package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "systemd-journal2gelf" { };
 
     };
   };
diff --git a/nixos/modules/services/logging/filebeat.nix b/nixos/modules/services/logging/filebeat.nix
index 5b5e7fd5ae89..071e001eb3c5 100644
--- a/nixos/modules/services/logging/filebeat.nix
+++ b/nixos/modules/services/logging/filebeat.nix
@@ -5,6 +5,7 @@ let
     attrValues
     literalExpression
     mkEnableOption
+    mkPackageOption
     mkIf
     mkOption
     types;
@@ -20,14 +21,8 @@ in
 
       enable = mkEnableOption (lib.mdDoc "filebeat");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.filebeat;
-        defaultText = literalExpression "pkgs.filebeat";
-        example = literalExpression "pkgs.filebeat7";
-        description = lib.mdDoc ''
-          The filebeat package to use.
-        '';
+      package = mkPackageOption pkgs "filebeat" {
+        example = "filebeat7";
       };
 
       inputs = mkOption {
diff --git a/nixos/modules/services/logging/fluentd.nix b/nixos/modules/services/logging/fluentd.nix
index 7764aafb2d1a..c8718f26db38 100644
--- a/nixos/modules/services/logging/fluentd.nix
+++ b/nixos/modules/services/logging/fluentd.nix
@@ -20,12 +20,7 @@ in {
         description = lib.mdDoc "Fluentd config.";
       };
 
-      package = mkOption {
-        type = types.path;
-        default = pkgs.fluentd;
-        defaultText = literalExpression "pkgs.fluentd";
-        description = lib.mdDoc "The fluentd package to use.";
-      };
+      package = mkPackageOption pkgs "fluentd" { };
 
       plugins = mkOption {
         type = types.listOf types.path;
diff --git a/nixos/modules/services/logging/heartbeat.nix b/nixos/modules/services/logging/heartbeat.nix
index a9ae11ec66e6..768ffe5315fe 100644
--- a/nixos/modules/services/logging/heartbeat.nix
+++ b/nixos/modules/services/logging/heartbeat.nix
@@ -20,14 +20,8 @@ in
 
       enable = mkEnableOption (lib.mdDoc "heartbeat");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.heartbeat;
-        defaultText = literalExpression "pkgs.heartbeat";
-        example = literalExpression "pkgs.heartbeat7";
-        description = lib.mdDoc ''
-          The heartbeat package to use.
-        '';
+      package = mkPackageOption pkgs "heartbeat" {
+        example = "heartbeat7";
       };
 
       name = mkOption {
diff --git a/nixos/modules/services/logging/journalbeat.nix b/nixos/modules/services/logging/journalbeat.nix
index e761380552de..80933d6a0f96 100644
--- a/nixos/modules/services/logging/journalbeat.nix
+++ b/nixos/modules/services/logging/journalbeat.nix
@@ -20,14 +20,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "journalbeat");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.journalbeat;
-        defaultText = literalExpression "pkgs.journalbeat";
-        description = lib.mdDoc ''
-          The journalbeat package to use
-        '';
-      };
+      package = mkPackageOption pkgs "journalbeat" { };
 
       name = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix
index 42d52a61639e..22292dbd931b 100644
--- a/nixos/modules/services/logging/logstash.nix
+++ b/nixos/modules/services/logging/logstash.nix
@@ -54,12 +54,7 @@ in
         description = lib.mdDoc "Enable logstash.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.logstash;
-        defaultText = literalExpression "pkgs.logstash";
-        description = lib.mdDoc "Logstash package to use.";
-      };
+      package = mkPackageOption pkgs "logstash" { };
 
       plugins = mkOption {
         type = types.listOf types.path;
diff --git a/nixos/modules/services/logging/syslog-ng.nix b/nixos/modules/services/logging/syslog-ng.nix
index 48d556b9459e..eea236263f7e 100644
--- a/nixos/modules/services/logging/syslog-ng.nix
+++ b/nixos/modules/services/logging/syslog-ng.nix
@@ -40,14 +40,7 @@ in {
           Whether to enable the syslog-ng daemon.
         '';
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.syslogng;
-        defaultText = literalExpression "pkgs.syslogng";
-        description = lib.mdDoc ''
-          The package providing syslog-ng binaries.
-        '';
-      };
+      package = mkPackageOption pkgs "syslogng" { };
       extraModulePaths = mkOption {
         type = types.listOf types.str;
         default = [];
diff --git a/nixos/modules/services/mail/exim.nix b/nixos/modules/services/mail/exim.nix
index 1d1258913b67..63d3fa54b23d 100644
--- a/nixos/modules/services/mail/exim.nix
+++ b/nixos/modules/services/mail/exim.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) literalExpression mkIf mkOption singleton types;
+  inherit (lib) literalExpression mkIf mkOption singleton types mkPackageOption;
   inherit (pkgs) coreutils;
   cfg = config.services.exim;
 in
@@ -57,12 +57,8 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.exim;
-        defaultText = literalExpression "pkgs.exim";
-        description = lib.mdDoc ''
-          The Exim derivation to use.
+      package = mkPackageOption pkgs "exim" {
+        extraDescription = ''
           This can be used to enable features such as LDAP or PAM support.
         '';
       };
diff --git a/nixos/modules/services/mail/offlineimap.nix b/nixos/modules/services/mail/offlineimap.nix
index 64fa09e83612..0166ec4e8d4e 100644
--- a/nixos/modules/services/mail/offlineimap.nix
+++ b/nixos/modules/services/mail/offlineimap.nix
@@ -22,12 +22,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.offlineimap;
-      defaultText = literalExpression "pkgs.offlineimap";
-      description = lib.mdDoc "Offlineimap derivation to use.";
-    };
+    package = mkPackageOption pkgs "offlineimap" { };
 
     path = mkOption {
       type = types.listOf types.path;
diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix
index 6ad3386d2d4e..a65c8e05a9ce 100644
--- a/nixos/modules/services/mail/opensmtpd.nix
+++ b/nixos/modules/services/mail/opensmtpd.nix
@@ -31,12 +31,7 @@ in {
         description = lib.mdDoc "Whether to enable the OpenSMTPD server.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.opensmtpd;
-        defaultText = literalExpression "pkgs.opensmtpd";
-        description = lib.mdDoc "The OpenSMTPD package to use.";
-      };
+      package = mkPackageOption pkgs "opensmtpd" { };
 
       setSendmail = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/mail/public-inbox.nix b/nixos/modules/services/mail/public-inbox.nix
index 4944d46fbd73..bab4e8bb8d10 100644
--- a/nixos/modules/services/mail/public-inbox.nix
+++ b/nixos/modules/services/mail/public-inbox.nix
@@ -144,12 +144,7 @@ in
 {
   options.services.public-inbox = {
     enable = mkEnableOption (lib.mdDoc "the public-inbox mail archiver");
-    package = mkOption {
-      type = types.package;
-      default = pkgs.public-inbox;
-      defaultText = literalExpression "pkgs.public-inbox";
-      description = lib.mdDoc "public-inbox package to use.";
-    };
+    package = mkPackageOption pkgs "public-inbox" { };
     path = mkOption {
       type = with types; listOf package;
       default = [];
diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix
index 4e29f567ed92..d9595b8e34ee 100644
--- a/nixos/modules/services/mail/roundcube.nix
+++ b/nixos/modules/services/mail/roundcube.nix
@@ -29,19 +29,8 @@ in
       description = lib.mdDoc "Hostname to use for the nginx vhost";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.roundcube;
-      defaultText = literalExpression "pkgs.roundcube";
-
-      example = literalExpression ''
-        roundcube.withPlugins (plugins: [ plugins.persistent_login ])
-      '';
-
-      description = lib.mdDoc ''
-        The package which contains roundcube's sources. Can be overridden to create
-        an environment which contains roundcube and third-party plugins.
-      '';
+    package = mkPackageOption pkgs "roundcube" {
+      example = "roundcube.withPlugins (plugins: [ plugins.persistent_login ])";
     };
 
     database = {
diff --git a/nixos/modules/services/matrix/appservice-discord.nix b/nixos/modules/services/matrix/appservice-discord.nix
index 6ce8718c35d8..c2c3abb79f97 100644
--- a/nixos/modules/services/matrix/appservice-discord.nix
+++ b/nixos/modules/services/matrix/appservice-discord.nix
@@ -15,14 +15,7 @@ in {
     services.matrix-appservice-discord = {
       enable = mkEnableOption (lib.mdDoc "a bridge between Matrix and Discord");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.matrix-appservice-discord;
-        defaultText = literalExpression "pkgs.matrix-appservice-discord";
-        description = lib.mdDoc ''
-          Which package of matrix-appservice-discord to use.
-        '';
-      };
+      package = mkPackageOption pkgs "matrix-appservice-discord" { };
 
       settings = mkOption rec {
         # TODO: switch to types.config.json as prescribed by RFC42 once it's implemented
diff --git a/nixos/modules/services/matrix/conduit.nix b/nixos/modules/services/matrix/conduit.nix
index 76af7ba22857..b0fc85dbda7b 100644
--- a/nixos/modules/services/matrix/conduit.nix
+++ b/nixos/modules/services/matrix/conduit.nix
@@ -20,14 +20,7 @@ in
         example = { RUST_BACKTRACE="yes"; };
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.matrix-conduit;
-        defaultText = lib.literalExpression "pkgs.matrix-conduit";
-        description = lib.mdDoc ''
-          Package of the conduit matrix server to use.
-        '';
-      };
+      package = mkPackageOption pkgs "matrix-conduit" { };
 
       settings = mkOption {
         type = types.submodule {
diff --git a/nixos/modules/services/misc/airsonic.nix b/nixos/modules/services/misc/airsonic.nix
index b8e9dcaf4663..6ba6ff5ca3cb 100644
--- a/nixos/modules/services/misc/airsonic.nix
+++ b/nixos/modules/services/misc/airsonic.nix
@@ -85,15 +85,12 @@ in {
         '';
       };
 
-      jre = mkOption {
-        type = types.package;
-        default = pkgs.jre8;
-        defaultText = literalExpression "pkgs.jre8";
-        description = lib.mdDoc ''
-          JRE package to use.
-
+      jre = mkPackageOption pkgs "jre8" {
+        extraDescription = ''
+          ::: {.note}
           Airsonic only supports Java 8, airsonic-advanced requires at least
           Java 11.
+          :::
         '';
       };
 
diff --git a/nixos/modules/services/misc/ananicy.nix b/nixos/modules/services/misc/ananicy.nix
index bc1b28efc0ba..01e1053c9e0e 100644
--- a/nixos/modules/services/misc/ananicy.nix
+++ b/nixos/modules/services/misc/ananicy.nix
@@ -15,21 +15,13 @@ in
     services.ananicy = {
       enable = mkEnableOption (lib.mdDoc "Ananicy, an auto nice daemon");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.ananicy;
-        defaultText = literalExpression "pkgs.ananicy";
-        example = literalExpression "pkgs.ananicy-cpp";
-        description = lib.mdDoc ''
-          Which ananicy package to use.
-        '';
+      package = mkPackageOption pkgs "ananicy" {
+        example = "ananicy-cpp";
       };
 
-      rulesProvider = mkOption {
-        type = types.package;
-        default = pkgs.ananicy;
-        defaultText = literalExpression "pkgs.ananicy";
-        example = literalExpression "pkgs.ananicy-cpp";
+      rulesProvider = mkPackageOption pkgs "ananicy" {
+        example = "ananicy-cpp";
+      } // {
         description = lib.mdDoc ''
           Which package to copy default rules,types,cgroups from.
         '';
diff --git a/nixos/modules/services/misc/ankisyncd.nix b/nixos/modules/services/misc/ankisyncd.nix
index 7be8dc7dab8f..e4de46e19a8f 100644
--- a/nixos/modules/services/misc/ankisyncd.nix
+++ b/nixos/modules/services/misc/ankisyncd.nix
@@ -24,12 +24,7 @@ in
     options.services.ankisyncd = {
       enable = mkEnableOption (lib.mdDoc "ankisyncd");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.ankisyncd;
-        defaultText = literalExpression "pkgs.ankisyncd";
-        description = lib.mdDoc "The package to use for the ankisyncd command.";
-      };
+      package = mkPackageOption pkgs "ankisyncd" { };
 
       host = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/apache-kafka.nix b/nixos/modules/services/misc/apache-kafka.nix
index 44db77ac754c..b7281a0d9d5f 100644
--- a/nixos/modules/services/misc/apache-kafka.nix
+++ b/nixos/modules/services/misc/apache-kafka.nix
@@ -141,12 +141,7 @@ in {
       ];
     };
 
-    package = mkOption {
-      description = lib.mdDoc "The kafka package to use";
-      default = pkgs.apacheKafka;
-      defaultText = literalExpression "pkgs.apacheKafka";
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "apacheKafka" { };
 
     jre = mkOption {
       description = lib.mdDoc "The JRE with which to run Kafka";
diff --git a/nixos/modules/services/misc/bcg.nix b/nixos/modules/services/misc/bcg.nix
index 214c89dbfe72..9da4a879cdd0 100644
--- a/nixos/modules/services/misc/bcg.nix
+++ b/nixos/modules/services/misc/bcg.nix
@@ -26,12 +26,7 @@ in
   options = {
     services.bcg = {
       enable = mkEnableOption (mdDoc "BigClown gateway");
-      package = mkOption {
-        default = pkgs.python3Packages.bcg;
-        defaultText = literalExpression "pkgs.python3Packages.bcg";
-        description = mdDoc "Which bcg derivation to use.";
-        type = types.package;
-      };
+      package = mkPackageOption pkgs [ "python3Packages" "bcg" ] { };
       environmentFiles = mkOption {
         type = types.listOf types.path;
         default = [];
diff --git a/nixos/modules/services/misc/cgminer.nix b/nixos/modules/services/misc/cgminer.nix
index a6fbfee73bad..ad6cbf50918d 100644
--- a/nixos/modules/services/misc/cgminer.nix
+++ b/nixos/modules/services/misc/cgminer.nix
@@ -33,12 +33,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "cgminer, an ASIC/FPGA/GPU miner for bitcoin and litecoin");
 
-      package = mkOption {
-        default = pkgs.cgminer;
-        defaultText = literalExpression "pkgs.cgminer";
-        description = lib.mdDoc "Which cgminer derivation to use.";
-        type = types.package;
-      };
+      package = mkPackageOption pkgs "cgminer" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/clipcat.nix b/nixos/modules/services/misc/clipcat.nix
index 0129de3a9efb..fb6442709530 100644
--- a/nixos/modules/services/misc/clipcat.nix
+++ b/nixos/modules/services/misc/clipcat.nix
@@ -9,12 +9,7 @@ in {
   options.services.clipcat= {
     enable = mkEnableOption (lib.mdDoc "Clipcat clipboard daemon");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.clipcat;
-      defaultText = literalExpression "pkgs.clipcat";
-      description = lib.mdDoc "clipcat derivation to use.";
-    };
+    package = mkPackageOption pkgs "clipcat" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/misc/clipmenu.nix b/nixos/modules/services/misc/clipmenu.nix
index 1cc8c4c47f7e..343167b1df2e 100644
--- a/nixos/modules/services/misc/clipmenu.nix
+++ b/nixos/modules/services/misc/clipmenu.nix
@@ -9,12 +9,7 @@ in {
   options.services.clipmenu = {
     enable = mkEnableOption (lib.mdDoc "clipmenu, the clipboard management daemon");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.clipmenu;
-      defaultText = literalExpression "pkgs.clipmenu";
-      description = lib.mdDoc "clipmenu derivation to use.";
-    };
+    package = mkPackageOption pkgs "clipmenu" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/misc/confd.nix b/nixos/modules/services/misc/confd.nix
index 17c1be57ccbc..93731547ede8 100644
--- a/nixos/modules/services/misc/confd.nix
+++ b/nixos/modules/services/misc/confd.nix
@@ -61,12 +61,7 @@ in {
       type = types.path;
     };
 
-    package = mkOption {
-      description = lib.mdDoc "Confd package to use.";
-      default = pkgs.confd;
-      defaultText = literalExpression "pkgs.confd";
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "confd" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix
index 13c57ce6b85b..ee342cbc2e47 100644
--- a/nixos/modules/services/misc/disnix.nix
+++ b/nixos/modules/services/misc/disnix.nix
@@ -27,12 +27,7 @@ in
 
       useWebServiceInterface = mkEnableOption (lib.mdDoc "the DisnixWebService interface running on Apache Tomcat");
 
-      package = mkOption {
-        type = types.path;
-        description = lib.mdDoc "The Disnix package";
-        default = pkgs.disnix;
-        defaultText = literalExpression "pkgs.disnix";
-      };
+      package = mkPackageOption pkgs "disnix" {};
 
       enableProfilePath = mkEnableOption (lib.mdDoc "exposing the Disnix profiles in the system's PATH");
 
diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix
index b0e910634637..e8fbc05423d3 100644
--- a/nixos/modules/services/misc/docker-registry.nix
+++ b/nixos/modules/services/misc/docker-registry.nix
@@ -47,12 +47,8 @@ in {
   options.services.dockerRegistry = {
     enable = mkEnableOption (lib.mdDoc "Docker Registry");
 
-    package = mkOption {
-      type = types.package;
-      description = mdDoc "Which Docker registry package to use.";
-      default = pkgs.docker-distribution;
-      defaultText = literalExpression "pkgs.docker-distribution";
-      example = literalExpression "pkgs.gitlab-container-registry";
+    package = mkPackageOption pkgs "docker-distribution" {
+      example = "gitlab-container-registry";
     };
 
     listenAddress = mkOption {
diff --git a/nixos/modules/services/misc/dwm-status.nix b/nixos/modules/services/misc/dwm-status.nix
index de3e28c41d27..351adf31d922 100644
--- a/nixos/modules/services/misc/dwm-status.nix
+++ b/nixos/modules/services/misc/dwm-status.nix
@@ -24,14 +24,8 @@ in
 
       enable = mkEnableOption (lib.mdDoc "dwm-status user service");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.dwm-status;
-        defaultText = literalExpression "pkgs.dwm-status";
-        example = literalExpression "pkgs.dwm-status.override { enableAlsaUtils = false; }";
-        description = lib.mdDoc ''
-          Which dwm-status package to use.
-        '';
+      package = mkPackageOption pkgs "dwm-status" {
+        example = "dwm-status.override { enableAlsaUtils = false; }";
       };
 
       order = mkOption {
diff --git a/nixos/modules/services/misc/freeswitch.nix b/nixos/modules/services/misc/freeswitch.nix
index b8b81e586944..a8f7b3d0c3ae 100644
--- a/nixos/modules/services/misc/freeswitch.nix
+++ b/nixos/modules/services/misc/freeswitch.nix
@@ -58,14 +58,7 @@ in {
           Also check available templates in [FreeSWITCH repository](https://github.com/signalwire/freeswitch/tree/master/conf).
         '';
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.freeswitch;
-        defaultText = literalExpression "pkgs.freeswitch";
-        description = lib.mdDoc ''
-          FreeSWITCH package.
-        '';
-      };
+      package = mkPackageOption pkgs "freeswitch" { };
     };
   };
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix
index be528a298991..f4305bea2ad7 100644
--- a/nixos/modules/services/misc/gitea.nix
+++ b/nixos/modules/services/misc/gitea.nix
@@ -51,12 +51,7 @@ in
         description = lib.mdDoc "Enable Gitea Service.";
       };
 
-      package = mkOption {
-        default = pkgs.gitea;
-        type = types.package;
-        defaultText = literalExpression "pkgs.gitea";
-        description = lib.mdDoc "gitea derivation to use";
-      };
+      package = mkPackageOption pkgs "gitea" { };
 
       useWizard = mkOption {
         default = false;
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index b399ccc38f58..6756d59cf367 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -258,41 +258,17 @@ in {
         '';
       };
 
-      packages.gitlab = mkOption {
-        type = types.package;
-        default = pkgs.gitlab;
-        defaultText = literalExpression "pkgs.gitlab";
-        description = lib.mdDoc "Reference to the gitlab package";
-        example = literalExpression "pkgs.gitlab-ee";
+      packages.gitlab = mkPackageOption pkgs "gitlab" {
+        example = "gitlab-ee";
       };
 
-      packages.gitlab-shell = mkOption {
-        type = types.package;
-        default = pkgs.gitlab-shell;
-        defaultText = literalExpression "pkgs.gitlab-shell";
-        description = lib.mdDoc "Reference to the gitlab-shell package";
-      };
+      packages.gitlab-shell = mkPackageOption pkgs "gitlab-shell" { };
 
-      packages.gitlab-workhorse = mkOption {
-        type = types.package;
-        default = pkgs.gitlab-workhorse;
-        defaultText = literalExpression "pkgs.gitlab-workhorse";
-        description = lib.mdDoc "Reference to the gitlab-workhorse package";
-      };
+      packages.gitlab-workhorse = mkPackageOption pkgs "gitlab-workhorse" { };
 
-      packages.gitaly = mkOption {
-        type = types.package;
-        default = pkgs.gitaly;
-        defaultText = literalExpression "pkgs.gitaly";
-        description = lib.mdDoc "Reference to the gitaly package";
-      };
+      packages.gitaly = mkPackageOption pkgs "gitaly" { };
 
-      packages.pages = mkOption {
-        type = types.package;
-        default = pkgs.gitlab-pages;
-        defaultText = literalExpression "pkgs.gitlab-pages";
-        description = lib.mdDoc "Reference to the gitlab-pages package";
-      };
+      packages.pages = mkPackageOption pkgs "gitlab-pages" { };
 
       statePath = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix
index b73528abaf65..e31eeaf8a30a 100644
--- a/nixos/modules/services/misc/gollum.nix
+++ b/nixos/modules/services/misc/gollum.nix
@@ -83,14 +83,7 @@ in
       description = lib.mdDoc "Specifies the path of the repository directory. If it does not exist, Gollum will create it on startup.";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.gollum;
-      defaultText = literalExpression "pkgs.gollum";
-      description = lib.mdDoc ''
-        The package used in the service
-      '';
-    };
+    package = mkPackageOption pkgs "gollum" { };
 
     user = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/misc/greenclip.nix b/nixos/modules/services/misc/greenclip.nix
index 45847af71141..ecfb864ab2b7 100644
--- a/nixos/modules/services/misc/greenclip.nix
+++ b/nixos/modules/services/misc/greenclip.nix
@@ -9,12 +9,7 @@ in {
   options.services.greenclip = {
     enable = mkEnableOption (lib.mdDoc "Greenclip daemon");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.haskellPackages.greenclip;
-      defaultText = literalExpression "pkgs.haskellPackages.greenclip";
-      description = lib.mdDoc "greenclip derivation to use.";
-    };
+    package = mkPackageOption pkgs [ "haskellPackages" "greenclip" ] { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/misc/heisenbridge.nix b/nixos/modules/services/misc/heisenbridge.nix
index 822a09d7cd4d..d7ce9c605c9e 100644
--- a/nixos/modules/services/misc/heisenbridge.nix
+++ b/nixos/modules/services/misc/heisenbridge.nix
@@ -25,14 +25,7 @@ in
   options.services.heisenbridge = {
     enable = mkEnableOption (lib.mdDoc "the Matrix to IRC bridge");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.heisenbridge;
-      defaultText = lib.literalExpression "pkgs.heisenbridge";
-      description = lib.mdDoc ''
-        Package of the application to run, exposed for overriding purposes.
-      '';
-    };
+    package = mkPackageOption pkgs "heisenbridge" { };
 
     homeserver = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/misc/jackett.nix b/nixos/modules/services/misc/jackett.nix
index b0edf0d18da4..c0bb0a575f01 100644
--- a/nixos/modules/services/misc/jackett.nix
+++ b/nixos/modules/services/misc/jackett.nix
@@ -35,12 +35,7 @@ in
         description = lib.mdDoc "Group under which Jackett runs.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.jackett;
-        defaultText = literalExpression "pkgs.jackett";
-        description = lib.mdDoc "Jackett package to use.";
-      };
+      package = mkPackageOption pkgs "jackett" { };
     };
   };
 
diff --git a/nixos/modules/services/misc/jellyfin.nix b/nixos/modules/services/misc/jellyfin.nix
index 43fdc09f4559..7042b491ffa4 100644
--- a/nixos/modules/services/misc/jellyfin.nix
+++ b/nixos/modules/services/misc/jellyfin.nix
@@ -16,14 +16,7 @@ in
         description = lib.mdDoc "User account under which Jellyfin runs.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.jellyfin;
-        defaultText = literalExpression "pkgs.jellyfin";
-        description = lib.mdDoc ''
-          Jellyfin package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "jellyfin" { };
 
       group = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/klipper.nix b/nixos/modules/services/misc/klipper.nix
index 9eb2fdb46593..a0eb409599b5 100644
--- a/nixos/modules/services/misc/klipper.nix
+++ b/nixos/modules/services/misc/klipper.nix
@@ -16,12 +16,7 @@ in
     services.klipper = {
       enable = mkEnableOption (lib.mdDoc "Klipper, the 3D printer firmware");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.klipper;
-        defaultText = literalExpression "pkgs.klipper";
-        description = lib.mdDoc "The Klipper package.";
-      };
+      package = mkPackageOption pkgs "klipper" { };
 
       logFile = mkOption {
         type = types.nullOr types.path;
diff --git a/nixos/modules/services/misc/libreddit.nix b/nixos/modules/services/misc/libreddit.nix
index fd58928d2821..02d71c198e78 100644
--- a/nixos/modules/services/misc/libreddit.nix
+++ b/nixos/modules/services/misc/libreddit.nix
@@ -15,12 +15,7 @@ in
     services.libreddit = {
       enable = mkEnableOption (lib.mdDoc "Private front-end for Reddit");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.libreddit;
-        defaultText = literalExpression "pkgs.libreddit";
-        description = lib.mdDoc "Libreddit package to use.";
-      };
+      package = mkPackageOption pkgs "libreddit" { };
 
       address = mkOption {
         default = "0.0.0.0";
diff --git a/nixos/modules/services/misc/lidarr.nix b/nixos/modules/services/misc/lidarr.nix
index 92b00054bdff..4dc0fc63863b 100644
--- a/nixos/modules/services/misc/lidarr.nix
+++ b/nixos/modules/services/misc/lidarr.nix
@@ -16,12 +16,7 @@ in
         description = lib.mdDoc "The directory where Lidarr stores its data files.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.lidarr;
-        defaultText = literalExpression "pkgs.lidarr";
-        description = lib.mdDoc "The Lidarr package to use";
-      };
+      package = mkPackageOption pkgs "lidarr" { };
 
       openFirewall = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/misc/mbpfan.nix b/nixos/modules/services/misc/mbpfan.nix
index 8f64fb2d9c52..ef56ea49d1a9 100644
--- a/nixos/modules/services/misc/mbpfan.nix
+++ b/nixos/modules/services/misc/mbpfan.nix
@@ -11,12 +11,7 @@ in {
   options.services.mbpfan = {
     enable = mkEnableOption (lib.mdDoc "mbpfan, fan controller daemon for Apple Macs and MacBooks");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.mbpfan;
-      defaultText = literalExpression "pkgs.mbpfan";
-      description = lib.mdDoc "The package used for the mbpfan daemon.";
-    };
+    package = mkPackageOption pkgs "mbpfan" { };
 
     verbose = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/misc/mediatomb.nix b/nixos/modules/services/misc/mediatomb.nix
index 335b1b684b1a..d421d74c53ad 100644
--- a/nixos/modules/services/misc/mediatomb.nix
+++ b/nixos/modules/services/misc/mediatomb.nix
@@ -215,14 +215,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.gerbera;
-        defaultText = literalExpression "pkgs.gerbera";
-        description = lib.mdDoc ''
-          Underlying package to be used with the module.
-        '';
-      };
+      package = mkPackageOption pkgs "gerbera" { };
 
       ps3Support = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/misc/moonraker.nix b/nixos/modules/services/misc/moonraker.nix
index 797e145c47a6..0ee7e898cf76 100644
--- a/nixos/modules/services/misc/moonraker.nix
+++ b/nixos/modules/services/misc/moonraker.nix
@@ -18,12 +18,9 @@ in {
     services.moonraker = {
       enable = mkEnableOption (lib.mdDoc "Moonraker, an API web server for Klipper");
 
-      package = mkOption {
-        type = with types; nullOr package;
-        default = pkgs.moonraker;
-        defaultText = literalExpression "pkgs.moonraker";
-        example = literalExpression "pkgs.moonraker.override { useGpiod = true; }";
-        description = lib.mdDoc "Moonraker package to use";
+      package = mkPackageOption pkgs "moonraker" {
+        nullable = true;
+        example = "moonraker.override { useGpiod = true; }";
       };
 
       klipperSocket = mkOption {
diff --git a/nixos/modules/services/misc/nitter.nix b/nixos/modules/services/misc/nitter.nix
index 77f5459d117c..c2c462d46bb5 100644
--- a/nixos/modules/services/misc/nitter.nix
+++ b/nixos/modules/services/misc/nitter.nix
@@ -54,12 +54,7 @@ in
     services.nitter = {
       enable = mkEnableOption (lib.mdDoc "Nitter");
 
-      package = mkOption {
-        default = pkgs.nitter;
-        type = types.package;
-        defaultText = literalExpression "pkgs.nitter";
-        description = lib.mdDoc "The nitter derivation to use.";
-      };
+      package = mkPackageOption pkgs "nitter" { };
 
       server = {
         address = mkOption {
diff --git a/nixos/modules/services/misc/ntfy-sh.nix b/nixos/modules/services/misc/ntfy-sh.nix
index 8fc1df93afb1..98134e94eeed 100644
--- a/nixos/modules/services/misc/ntfy-sh.nix
+++ b/nixos/modules/services/misc/ntfy-sh.nix
@@ -12,12 +12,7 @@ in
   options.services.ntfy-sh = {
     enable = mkEnableOption (mdDoc "[ntfy-sh](https://ntfy.sh), a push notification service");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.ntfy-sh;
-      defaultText = literalExpression "pkgs.ntfy-sh";
-      description = mdDoc "The ntfy.sh package to use.";
-    };
+    package = mkPackageOption pkgs "ntfy-sh" { };
 
     user = mkOption {
       default = "ntfy-sh";
diff --git a/nixos/modules/services/misc/nzbhydra2.nix b/nixos/modules/services/misc/nzbhydra2.nix
index 47d08135f57e..536a4e4b0075 100644
--- a/nixos/modules/services/misc/nzbhydra2.nix
+++ b/nixos/modules/services/misc/nzbhydra2.nix
@@ -22,12 +22,7 @@ in {
           lib.mdDoc "Open ports in the firewall for the NZBHydra2 web interface.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.nzbhydra2;
-        defaultText = literalExpression "pkgs.nzbhydra2";
-        description = lib.mdDoc "NZBHydra2 package to use.";
-      };
+      package = mkPackageOption pkgs "nzbhydra2" { };
     };
   };
 
diff --git a/nixos/modules/services/misc/paperless.nix b/nixos/modules/services/misc/paperless.nix
index 1e0a8d0f928e..b3bc7d89009d 100644
--- a/nixos/modules/services/misc/paperless.nix
+++ b/nixos/modules/services/misc/paperless.nix
@@ -194,12 +194,7 @@ in
       description = lib.mdDoc "User under which Paperless runs.";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.paperless-ngx;
-      defaultText = literalExpression "pkgs.paperless-ngx";
-      description = lib.mdDoc "The Paperless package to use.";
-    };
+    package = mkPackageOption pkgs "paperless-ngx" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index 7fc76028c02a..164801605713 100644
--- a/nixos/modules/services/misc/plex.nix
+++ b/nixos/modules/services/misc/plex.nix
@@ -93,13 +93,10 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.plex;
-        defaultText = literalExpression "pkgs.plex";
-        description = lib.mdDoc ''
-          The Plex package to use. Plex subscribers may wish to use their own
-          package here, pointing to subscriber-only server versions.
+      package = mkPackageOption pkgs "plex" {
+        extraDescription = ''
+          Plex subscribers may wish to use their own package here,
+          pointing to subscriber-only server versions.
         '';
       };
     };
diff --git a/nixos/modules/services/misc/portunus.nix b/nixos/modules/services/misc/portunus.nix
index d18881986970..3299b6404c2b 100644
--- a/nixos/modules/services/misc/portunus.nix
+++ b/nixos/modules/services/misc/portunus.nix
@@ -26,12 +26,7 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.portunus;
-      defaultText = lib.literalExpression "pkgs.portunus";
-      description = lib.mdDoc "The Portunus package to use.";
-    };
+    package = mkPackageOption pkgs "portunus" { };
 
     seedPath = mkOption {
       type = types.nullOr types.path;
diff --git a/nixos/modules/services/misc/radarr.nix b/nixos/modules/services/misc/radarr.nix
index 834b092c0d14..618341cf614f 100644
--- a/nixos/modules/services/misc/radarr.nix
+++ b/nixos/modules/services/misc/radarr.nix
@@ -11,13 +11,7 @@ in
     services.radarr = {
       enable = mkEnableOption (lib.mdDoc "Radarr");
 
-      package = mkOption {
-        description = lib.mdDoc "Radarr package to use";
-        default = pkgs.radarr;
-        defaultText = literalExpression "pkgs.radarr";
-        example = literalExpression "pkgs.radarr";
-        type = types.package;
-      };
+      package = mkPackageOption pkgs "radarr" { };
 
       dataDir = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/misc/readarr.nix b/nixos/modules/services/misc/readarr.nix
index dd4fef6e598d..3c84b13485a4 100644
--- a/nixos/modules/services/misc/readarr.nix
+++ b/nixos/modules/services/misc/readarr.nix
@@ -16,12 +16,7 @@ in
         description = lib.mdDoc "The directory where Readarr stores its data files.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.readarr;
-        defaultText = literalExpression "pkgs.readarr";
-        description = lib.mdDoc "The Readarr package to use";
-      };
+      package = mkPackageOption pkgs "readarr" { };
 
       openFirewall = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/misc/redmine.nix b/nixos/modules/services/misc/redmine.nix
index 20fa71507b6b..e3941d2e29de 100644
--- a/nixos/modules/services/misc/redmine.nix
+++ b/nixos/modules/services/misc/redmine.nix
@@ -1,7 +1,8 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) mkBefore mkDefault mkEnableOption mkIf mkOption mkRemovedOptionModule types;
+  inherit (lib) mkBefore mkDefault mkEnableOption mkPackageOption
+                mkIf mkOption mkRemovedOptionModule types;
   inherit (lib) concatStringsSep literalExpression mapAttrsToList;
   inherit (lib) optional optionalAttrs optionalString;
 
@@ -51,12 +52,8 @@ in
     services.redmine = {
       enable = mkEnableOption (lib.mdDoc "Redmine");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.redmine;
-        defaultText = literalExpression "pkgs.redmine";
-        description = lib.mdDoc "Which Redmine package to use.";
-        example = literalExpression "pkgs.redmine.override { ruby = pkgs.ruby_2_7; }";
+      package = mkPackageOption pkgs "redmine" {
+        example = "redmine.override { ruby = pkgs.ruby_2_7; }";
       };
 
       user = mkOption {
diff --git a/nixos/modules/services/misc/rippled.nix b/nixos/modules/services/misc/rippled.nix
index d14b6421b742..68a831894250 100644
--- a/nixos/modules/services/misc/rippled.nix
+++ b/nixos/modules/services/misc/rippled.nix
@@ -209,12 +209,7 @@ in
     services.rippled = {
       enable = mkEnableOption (lib.mdDoc "rippled");
 
-      package = mkOption {
-        description = lib.mdDoc "Which rippled package to use.";
-        type = types.package;
-        default = pkgs.rippled;
-        defaultText = literalExpression "pkgs.rippled";
-      };
+      package = mkPackageOption pkgs "rippled" { };
 
       ports = mkOption {
         description = lib.mdDoc "Ports exposed by rippled";
diff --git a/nixos/modules/services/misc/rmfakecloud.nix b/nixos/modules/services/misc/rmfakecloud.nix
index 1cdfdeceabcd..979f4f14d383 100644
--- a/nixos/modules/services/misc/rmfakecloud.nix
+++ b/nixos/modules/services/misc/rmfakecloud.nix
@@ -11,14 +11,11 @@ in {
     services.rmfakecloud = {
       enable = mkEnableOption (lib.mdDoc "rmfakecloud remarkable self-hosted cloud");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.rmfakecloud;
-        defaultText = literalExpression "pkgs.rmfakecloud";
-        description = lib.mdDoc ''
-          rmfakecloud package to use.
-
+      package = mkPackageOption pkgs "rmfakecloud" {
+        extraDescription = ''
+          ::: {.note}
           The default does not include the web user interface.
+          :::
         '';
       };
 
diff --git a/nixos/modules/services/misc/sickbeard.nix b/nixos/modules/services/misc/sickbeard.nix
index bd8d8d8fa7cc..f141660ced86 100644
--- a/nixos/modules/services/misc/sickbeard.nix
+++ b/nixos/modules/services/misc/sickbeard.nix
@@ -22,12 +22,9 @@ in
         default = false;
         description = lib.mdDoc "Whether to enable the sickbeard server.";
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.sickbeard;
-        defaultText = literalExpression "pkgs.sickbeard";
-        example = literalExpression "pkgs.sickrage";
-        description =lib.mdDoc ''
+      package = mkPackageOption pkgs "sickbeard" {
+        example = "sickrage";
+        extraDescription = ''
           Enable `pkgs.sickrage` or `pkgs.sickgear`
           as an alternative to SickBeard
         '';
diff --git a/nixos/modules/services/misc/sonarr.nix b/nixos/modules/services/misc/sonarr.nix
index 65c51d9677d9..ec59988d2b9a 100644
--- a/nixos/modules/services/misc/sonarr.nix
+++ b/nixos/modules/services/misc/sonarr.nix
@@ -36,14 +36,7 @@ in
         description = lib.mdDoc "Group under which Sonaar runs.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.sonarr;
-        defaultText = literalExpression "pkgs.sonarr";
-        description = lib.mdDoc ''
-          Sonarr package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "sonarr" { };
     };
   };
 
diff --git a/nixos/modules/services/misc/sourcehut/default.nix b/nixos/modules/services/misc/sourcehut/default.nix
index af9768c98ac3..aa803d3bb693 100644
--- a/nixos/modules/services/misc/sourcehut/default.nix
+++ b/nixos/modules/services/misc/sourcehut/default.nix
@@ -5,7 +5,7 @@ let
   inherit (lib) generators maintainers types;
   inherit (lib.attrsets) attrValues filterAttrs mapAttrs mapAttrsToList recursiveUpdate;
   inherit (lib.lists) flatten optional optionals;
-  inherit (lib.options) literalExpression mkEnableOption mkOption;
+  inherit (lib.options) literalExpression mkEnableOption mkOption mkPackageOption;
   inherit (lib.strings) concatMapStringsSep concatStringsSep optionalString versionOlder;
   inherit (lib.trivial) mapNullable;
   inherit (lib.modules) mkBefore mkDefault mkForce mkIf mkMerge
@@ -680,14 +680,8 @@ in
     };
 
     git = {
-      package = mkOption {
-        type = types.package;
-        default = pkgs.git;
-        defaultText = literalExpression "pkgs.git";
-        example = literalExpression "pkgs.gitFull";
-        description = lib.mdDoc ''
-          Git package for git.sr.ht. This can help silence collisions.
-        '';
+      package = mkPackageOption pkgs "git" {
+        example = "gitFull";
       };
       fcgiwrap.preforkProcess = mkOption {
         description = lib.mdDoc "Number of fcgiwrap processes to prefork.";
@@ -697,14 +691,7 @@ in
     };
 
     hg = {
-      package = mkOption {
-        type = types.package;
-        default = pkgs.mercurial;
-        defaultText = literalExpression "pkgs.mercurial";
-        description = lib.mdDoc ''
-          Mercurial package for hg.sr.ht. This can help silence collisions.
-        '';
-      };
+      package = mkPackageOption pkgs "mercurial" { };
       cloneBundles = mkOption {
         type = types.bool;
         default = false;
diff --git a/nixos/modules/services/misc/spice-webdavd.nix b/nixos/modules/services/misc/spice-webdavd.nix
index 6c817e429ac6..2b4304365618 100644
--- a/nixos/modules/services/misc/spice-webdavd.nix
+++ b/nixos/modules/services/misc/spice-webdavd.nix
@@ -9,12 +9,7 @@ in
     services.spice-webdavd = {
       enable = mkEnableOption (lib.mdDoc "the spice guest webdav proxy daemon");
 
-      package = mkOption {
-        default = pkgs.phodav;
-        defaultText = literalExpression "pkgs.phodav";
-        type = types.package;
-        description = lib.mdDoc "spice-webdavd provider package to use.";
-      };
+      package = mkPackageOption pkgs "phodav" { };
     };
   };
 
diff --git a/nixos/modules/services/misc/tandoor-recipes.nix b/nixos/modules/services/misc/tandoor-recipes.nix
index 63d3e3d2a857..2d7d29b2e717 100644
--- a/nixos/modules/services/misc/tandoor-recipes.nix
+++ b/nixos/modules/services/misc/tandoor-recipes.nix
@@ -71,12 +71,7 @@ in
       };
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.tandoor-recipes;
-      defaultText = literalExpression "pkgs.tandoor-recipes";
-      description = lib.mdDoc "The Tandoor Recipes package to use.";
-    };
+    package = mkPackageOption pkgs "tandoor-recipes" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/misc/tautulli.nix b/nixos/modules/services/misc/tautulli.nix
index b29e9dc0c8d5..e379628c8ce6 100644
--- a/nixos/modules/services/misc/tautulli.nix
+++ b/nixos/modules/services/misc/tautulli.nix
@@ -50,14 +50,7 @@ in
         description = lib.mdDoc "Group under which Tautulli runs.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.tautulli;
-        defaultText = literalExpression "pkgs.tautulli";
-        description = lib.mdDoc ''
-          The Tautulli package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "tautulli" { };
     };
   };
 
diff --git a/nixos/modules/services/misc/tp-auto-kbbl.nix b/nixos/modules/services/misc/tp-auto-kbbl.nix
index 1076c814e86c..f6f2d49733e6 100644
--- a/nixos/modules/services/misc/tp-auto-kbbl.nix
+++ b/nixos/modules/services/misc/tp-auto-kbbl.nix
@@ -11,12 +11,7 @@ in {
     services.tp-auto-kbbl = {
       enable = mkEnableOption (lib.mdDoc "auto toggle keyboard back-lighting on Thinkpads (and maybe other laptops) for Linux");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.tp-auto-kbbl;
-        defaultText = literalExpression "pkgs.tp-auto-kbbl";
-        description = lib.mdDoc "Package providing {command}`tp-auto-kbbl`.";
-      };
+      package = mkPackageOption pkgs "tp-auto-kbbl" { };
 
       arguments = mkOption {
         type = types.listOf types.str;
diff --git a/nixos/modules/services/misc/xmrig.nix b/nixos/modules/services/misc/xmrig.nix
index f75b47ffeced..8ad2d049f8a9 100644
--- a/nixos/modules/services/misc/xmrig.nix
+++ b/nixos/modules/services/misc/xmrig.nix
@@ -15,12 +15,8 @@ with lib;
     services.xmrig = {
       enable = mkEnableOption (lib.mdDoc "XMRig Mining Software");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.xmrig;
-        defaultText = literalExpression "pkgs.xmrig";
-        example = literalExpression "pkgs.xmrig-mo";
-        description = lib.mdDoc "XMRig package to use.";
+      package = mkPackageOption pkgs "xmrig" {
+        example = "xmrig-mo";
       };
 
       settings = mkOption {
diff --git a/nixos/modules/services/misc/zookeeper.nix b/nixos/modules/services/misc/zookeeper.nix
index fb51be698e72..b1c0b80648c6 100644
--- a/nixos/modules/services/misc/zookeeper.nix
+++ b/nixos/modules/services/misc/zookeeper.nix
@@ -103,12 +103,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      description = lib.mdDoc "The zookeeper package to use";
-      default = pkgs.zookeeper;
-      defaultText = literalExpression "pkgs.zookeeper";
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "zookeeper" { };
 
     jre = mkOption {
       description = lib.mdDoc "The JRE with which to run Zookeeper";
diff --git a/nixos/modules/services/monitoring/arbtt.nix b/nixos/modules/services/monitoring/arbtt.nix
index f07ecc5d5dd0..a1a228d6e420 100644
--- a/nixos/modules/services/monitoring/arbtt.nix
+++ b/nixos/modules/services/monitoring/arbtt.nix
@@ -9,14 +9,7 @@ in {
     services.arbtt = {
       enable = mkEnableOption (lib.mdDoc "Arbtt statistics capture service");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.haskellPackages.arbtt;
-        defaultText = literalExpression "pkgs.haskellPackages.arbtt";
-        description = lib.mdDoc ''
-          The package to use for the arbtt binaries.
-        '';
-      };
+      package = mkPackageOption pkgs [ "haskellPackages" "arbtt" ] { };
 
       logFile = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/monitoring/bosun.nix b/nixos/modules/services/monitoring/bosun.nix
index 1dc19743461b..fb412d43ec27 100644
--- a/nixos/modules/services/monitoring/bosun.nix
+++ b/nixos/modules/services/monitoring/bosun.nix
@@ -24,14 +24,7 @@ in {
 
       enable = mkEnableOption (lib.mdDoc "bosun");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.bosun;
-        defaultText = literalExpression "pkgs.bosun";
-        description = lib.mdDoc ''
-          bosun binary to use.
-        '';
-      };
+      package = mkPackageOption pkgs "bosun" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix
index 5d525995c67a..3e62ef422bad 100644
--- a/nixos/modules/services/monitoring/collectd.nix
+++ b/nixos/modules/services/monitoring/collectd.nix
@@ -41,14 +41,7 @@ in {
       type = types.bool;
     };
 
-    package = mkOption {
-      default = pkgs.collectd;
-      defaultText = literalExpression "pkgs.collectd";
-      description = lib.mdDoc ''
-        Which collectd package to use.
-      '';
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "collectd" { };
 
     buildMinimalPackage = mkOption {
       default = false;
diff --git a/nixos/modules/services/monitoring/datadog-agent.nix b/nixos/modules/services/monitoring/datadog-agent.nix
index 1736b0c088a3..7b07c80c8d7b 100644
--- a/nixos/modules/services/monitoring/datadog-agent.nix
+++ b/nixos/modules/services/monitoring/datadog-agent.nix
@@ -51,16 +51,13 @@ in {
   options.services.datadog-agent = {
     enable = mkEnableOption (lib.mdDoc "Datadog-agent v7 monitoring service");
 
-    package = mkOption {
-      default = pkgs.datadog-agent;
-      defaultText = literalExpression "pkgs.datadog-agent";
-      description = lib.mdDoc ''
-        Which DataDog v7 agent package to use. Note that the provided
-        package is expected to have an overridable `pythonPackages`-attribute
-        which configures the Python environment with the Datadog
-        checks.
+    package = mkPackageOption pkgs "datadog-agent" {
+      extraDescription = ''
+        ::: {.note}
+        The provided package is expected to have an overridable `pythonPackages`-attribute
+        which configures the Python environment with the Datadog checks.
+        :::
       '';
-      type = types.package;
     };
 
     apiKeyFile = mkOption {
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
index f84d677f14d8..62c50490ee99 100644
--- a/nixos/modules/services/monitoring/grafana.nix
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -310,12 +310,7 @@ in
       apply = x: if isList x then lib.unique x else x;
     };
 
-    package = mkOption {
-      description = lib.mdDoc "Package to use.";
-      default = pkgs.grafana;
-      defaultText = literalExpression "pkgs.grafana";
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "grafana" { };
 
     dataDir = mkOption {
       description = lib.mdDoc "Data directory.";
diff --git a/nixos/modules/services/monitoring/heapster.nix b/nixos/modules/services/monitoring/heapster.nix
index fc63276b62f7..9f9c24949fc9 100644
--- a/nixos/modules/services/monitoring/heapster.nix
+++ b/nixos/modules/services/monitoring/heapster.nix
@@ -26,12 +26,7 @@ in {
       type = types.separatedString " ";
     };
 
-    package = mkOption {
-      description = lib.mdDoc "Package to use by heapster";
-      default = pkgs.heapster;
-      defaultText = literalExpression "pkgs.heapster";
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "heapster" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/monitoring/karma.nix b/nixos/modules/services/monitoring/karma.nix
index 85dbc81f443f..9883ec4fe841 100644
--- a/nixos/modules/services/monitoring/karma.nix
+++ b/nixos/modules/services/monitoring/karma.nix
@@ -8,14 +8,7 @@ in
   options.services.karma = {
     enable = mkEnableOption (mdDoc "the Karma dashboard service");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.karma;
-      defaultText = literalExpression "pkgs.karma";
-      description = mdDoc ''
-        The Karma package that should be used.
-      '';
-    };
+    package = mkPackageOption pkgs "karma" { };
 
     configFile = mkOption {
       type = types.path;
diff --git a/nixos/modules/services/monitoring/kthxbye.nix b/nixos/modules/services/monitoring/kthxbye.nix
index 3f988dcb722f..3be002445722 100644
--- a/nixos/modules/services/monitoring/kthxbye.nix
+++ b/nixos/modules/services/monitoring/kthxbye.nix
@@ -9,14 +9,7 @@ in
   options.services.kthxbye = {
     enable = mkEnableOption (mdDoc "kthxbye alert acknowledgement management daemon");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.kthxbye;
-      defaultText = literalExpression "pkgs.kthxbye";
-      description = mdDoc ''
-        The kthxbye package that should be used.
-      '';
-    };
+    package = mkPackageOption pkgs "kthxbye" { };
 
     openFirewall = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/monitoring/metricbeat.nix b/nixos/modules/services/monitoring/metricbeat.nix
index 310c9d8ed509..c3320f695564 100644
--- a/nixos/modules/services/monitoring/metricbeat.nix
+++ b/nixos/modules/services/monitoring/metricbeat.nix
@@ -5,6 +5,7 @@ let
     attrValues
     literalExpression
     mkEnableOption
+    mkPackageOption
     mkIf
     mkOption
     types
@@ -21,14 +22,8 @@ in
 
       enable = mkEnableOption (lib.mdDoc "metricbeat");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.metricbeat;
-        defaultText = literalExpression "pkgs.metricbeat";
-        example = literalExpression "pkgs.metricbeat7";
-        description = lib.mdDoc ''
-          The metricbeat package to use
-        '';
+      package = mkPackageOption pkgs "metricbeat" {
+        example = "metricbeat7";
       };
 
       modules = mkOption {
diff --git a/nixos/modules/services/monitoring/mimir.nix b/nixos/modules/services/monitoring/mimir.nix
index 6ed139b22974..117cbf6a4a8c 100644
--- a/nixos/modules/services/monitoring/mimir.nix
+++ b/nixos/modules/services/monitoring/mimir.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) escapeShellArgs mkEnableOption mkIf mkOption types;
+  inherit (lib) escapeShellArgs mkEnableOption mkPackageOption mkIf mkOption types;
 
   cfg = config.services.mimir;
 
@@ -26,12 +26,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      default = pkgs.mimir;
-      defaultText = lib.literalExpression "pkgs.mimir";
-      type = types.package;
-      description = lib.mdDoc ''Mimir package to use.'';
-    };
+    package = mkPackageOption pkgs "mimir" { };
 
     extraFlags = mkOption {
       type = types.listOf types.str;
diff --git a/nixos/modules/services/monitoring/netdata.nix b/nixos/modules/services/monitoring/netdata.nix
index de0e044453ee..78b12537e27f 100644
--- a/nixos/modules/services/monitoring/netdata.nix
+++ b/nixos/modules/services/monitoring/netdata.nix
@@ -52,12 +52,7 @@ in {
     services.netdata = {
       enable = mkEnableOption (lib.mdDoc "netdata");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.netdata;
-        defaultText = literalExpression "pkgs.netdata";
-        description = lib.mdDoc "Netdata package to use.";
-      };
+      package = mkPackageOption pkgs "netdata" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/monitoring/opentelemetry-collector.nix b/nixos/modules/services/monitoring/opentelemetry-collector.nix
index 1d211b689777..83ad550dcdf3 100644
--- a/nixos/modules/services/monitoring/opentelemetry-collector.nix
+++ b/nixos/modules/services/monitoring/opentelemetry-collector.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) mkEnableOption mkIf mkOption types getExe;
+  inherit (lib) mkEnableOption mkPackageOption mkIf mkOption types getExe;
 
   cfg = config.services.opentelemetry-collector;
   opentelemetry-collector = cfg.package;
@@ -11,12 +11,7 @@ in {
   options.services.opentelemetry-collector = {
     enable = mkEnableOption (lib.mdDoc "Opentelemetry Collector");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.opentelemetry-collector;
-      defaultText = lib.literalExpression "pkgs.opentelemetry-collector";
-      description = lib.mdDoc "The opentelemetry-collector package to use.";
-    };
+    package = mkPackageOption pkgs "opentelemetry-collector" { };
 
     settings = mkOption {
       type = settingsFormat.type;
diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager-irc-relay.nix b/nixos/modules/services/monitoring/prometheus/alertmanager-irc-relay.nix
index b81d5f6db5e0..9b9bafa09441 100644
--- a/nixos/modules/services/monitoring/prometheus/alertmanager-irc-relay.nix
+++ b/nixos/modules/services/monitoring/prometheus/alertmanager-irc-relay.nix
@@ -12,12 +12,7 @@ in
   options.services.prometheus.alertmanagerIrcRelay = {
     enable = mkEnableOption (mdDoc "Alertmanager IRC Relay");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.alertmanager-irc-relay;
-      defaultText = literalExpression "pkgs.alertmanager-irc-relay";
-      description = mdDoc "Alertmanager IRC Relay package to use.";
-    };
+    package = mkPackageOption pkgs "alertmanager-irc-relay" { };
 
     extraFlags = mkOption {
       type = types.listOf types.str;
diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
index 5fb543ec6195..4fd630015f35 100644
--- a/nixos/modules/services/monitoring/prometheus/alertmanager.nix
+++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
@@ -44,14 +44,7 @@ in {
     services.prometheus.alertmanager = {
       enable = mkEnableOption (lib.mdDoc "Prometheus Alertmanager");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.prometheus-alertmanager;
-        defaultText = literalExpression "pkgs.alertmanager";
-        description = lib.mdDoc ''
-          Package that should be used for alertmanager.
-        '';
-      };
+      package = mkPackageOption pkgs "prometheus-alertmanager" { };
 
       configuration = mkOption {
         type = types.nullOr types.attrs;
diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix
index a38855ccd408..90ea56658b02 100644
--- a/nixos/modules/services/monitoring/prometheus/default.nix
+++ b/nixos/modules/services/monitoring/prometheus/default.nix
@@ -1564,14 +1564,7 @@ in
 
     enable = mkEnableOption (lib.mdDoc "Prometheus monitoring daemon");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.prometheus;
-      defaultText = literalExpression "pkgs.prometheus";
-      description = lib.mdDoc ''
-        The prometheus package that should be used.
-      '';
-    };
+    package = mkPackageOption pkgs "prometheus" { };
 
     port = mkOption {
       type = types.port;
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/pve.nix b/nixos/modules/services/monitoring/prometheus/exporters/pve.nix
index f95412efd7dd..20ee2e4b3238 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/pve.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/pve.nix
@@ -15,15 +15,7 @@ in
 {
   port = 9221;
   extraOpts = {
-    package = mkOption {
-      type = types.package;
-      default = pkgs.prometheus-pve-exporter;
-      defaultText = literalExpression "pkgs.prometheus-pve-exporter";
-      example = literalExpression "pkgs.prometheus-pve-exporter";
-      description = lib.mdDoc ''
-        The package to use for prometheus-pve-exporter
-      '';
-    };
+    package = mkPackageOption pkgs "prometheus-pve-exporter" { };
 
     environmentFile = mkOption {
       type = with types; nullOr path;
diff --git a/nixos/modules/services/monitoring/prometheus/pushgateway.nix b/nixos/modules/services/monitoring/prometheus/pushgateway.nix
index f5c114c92752..e93924e4fba8 100644
--- a/nixos/modules/services/monitoring/prometheus/pushgateway.nix
+++ b/nixos/modules/services/monitoring/prometheus/pushgateway.nix
@@ -23,14 +23,7 @@ in {
     services.prometheus.pushgateway = {
       enable = mkEnableOption (lib.mdDoc "Prometheus Pushgateway");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.prometheus-pushgateway;
-        defaultText = literalExpression "pkgs.prometheus-pushgateway";
-        description = lib.mdDoc ''
-          Package that should be used for the prometheus pushgateway.
-        '';
-      };
+      package = mkPackageOption pkgs "prometheus-pushgateway" { };
 
       web.listen-address = mkOption {
         type = types.nullOr types.str;
diff --git a/nixos/modules/services/monitoring/scollector.nix b/nixos/modules/services/monitoring/scollector.nix
index 48be309c9599..0011d56a066a 100644
--- a/nixos/modules/services/monitoring/scollector.nix
+++ b/nixos/modules/services/monitoring/scollector.nix
@@ -40,14 +40,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.scollector;
-        defaultText = literalExpression "pkgs.scollector";
-        description = lib.mdDoc ''
-          scollector binary to use.
-        '';
-      };
+      package = mkPackageOption pkgs "scollector" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/monitoring/telegraf.nix b/nixos/modules/services/monitoring/telegraf.nix
index a957ef4d81db..ee28ee03adf3 100644
--- a/nixos/modules/services/monitoring/telegraf.nix
+++ b/nixos/modules/services/monitoring/telegraf.nix
@@ -13,12 +13,7 @@ in {
     services.telegraf = {
       enable = mkEnableOption (lib.mdDoc "telegraf server");
 
-      package = mkOption {
-        default = pkgs.telegraf;
-        defaultText = literalExpression "pkgs.telegraf";
-        description = lib.mdDoc "Which telegraf derivation to use";
-        type = types.package;
-      };
+      package = mkPackageOption pkgs "telegraf" { };
 
       environmentFiles = mkOption {
         type = types.listOf types.path;
diff --git a/nixos/modules/services/monitoring/uptime-kuma.nix b/nixos/modules/services/monitoring/uptime-kuma.nix
index 7027046b2425..f3a41de7536a 100644
--- a/nixos/modules/services/monitoring/uptime-kuma.nix
+++ b/nixos/modules/services/monitoring/uptime-kuma.nix
@@ -13,12 +13,7 @@ in
     services.uptime-kuma = {
       enable = mkEnableOption (mdDoc "Uptime Kuma, this assumes a reverse proxy to be set");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.uptime-kuma;
-        defaultText = literalExpression "pkgs.uptime-kuma";
-        description = lib.mdDoc "Uptime Kuma package to use.";
-      };
+      package = mkPackageOption pkgs "uptime-kuma" { };
 
       appriseSupport = mkEnableOption (mdDoc "apprise support for notifications");
 
diff --git a/nixos/modules/services/monitoring/vmagent.nix b/nixos/modules/services/monitoring/vmagent.nix
index 0e2ffb31c57c..bd3ef756959d 100644
--- a/nixos/modules/services/monitoring/vmagent.nix
+++ b/nixos/modules/services/monitoring/vmagent.nix
@@ -23,14 +23,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      default = pkgs.vmagent;
-      defaultText = lib.literalMD "pkgs.vmagent";
-      type = types.package;
-      description = lib.mdDoc ''
-        vmagent package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "vmagent" { };
 
     dataDir = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/monitoring/vmalert.nix b/nixos/modules/services/monitoring/vmalert.nix
index 27fb34e199b5..1c64f7e100fa 100644
--- a/nixos/modules/services/monitoring/vmalert.nix
+++ b/nixos/modules/services/monitoring/vmalert.nix
@@ -22,14 +22,7 @@ in
   options.services.vmalert = {
     enable = mkEnableOption (mdDoc "vmalert");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.victoriametrics;
-      defaultText = "pkgs.victoriametrics";
-      description = mdDoc ''
-        The VictoriaMetrics derivation to use.
-      '';
-    };
+    package = mkPackageOption pkgs "victoriametrics" { };
 
     settings = mkOption {
       type = types.submodule {
diff --git a/nixos/modules/services/monitoring/zabbix-agent.nix b/nixos/modules/services/monitoring/zabbix-agent.nix
index b497ecbcdb6c..b195366123ab 100644
--- a/nixos/modules/services/monitoring/zabbix-agent.nix
+++ b/nixos/modules/services/monitoring/zabbix-agent.nix
@@ -3,7 +3,7 @@
 let
   cfg = config.services.zabbixAgent;
 
-  inherit (lib) mkDefault mkEnableOption mkIf mkMerge mkOption;
+  inherit (lib) mkDefault mkEnableOption mkPackageOption mkIf mkMerge mkOption;
   inherit (lib) attrValues concatMapStringsSep literalExpression optionalString types;
   inherit (lib.generators) toKeyValue;
 
@@ -31,12 +31,7 @@ in
     services.zabbixAgent = {
       enable = mkEnableOption (lib.mdDoc "the Zabbix Agent");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.zabbix.agent;
-        defaultText = literalExpression "pkgs.zabbix.agent";
-        description = lib.mdDoc "The Zabbix package to use.";
-      };
+      package = mkPackageOption pkgs [ "zabbix" "agent" ] { };
 
       extraPackages = mkOption {
         type = types.listOf types.package;
diff --git a/nixos/modules/services/network-filesystems/kubo.nix b/nixos/modules/services/network-filesystems/kubo.nix
index bc746bed31f2..fbf9b32a2b25 100644
--- a/nixos/modules/services/network-filesystems/kubo.nix
+++ b/nixos/modules/services/network-filesystems/kubo.nix
@@ -101,12 +101,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "Interplanetary File System (WARNING: may cause severe network degradation)");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.kubo;
-        defaultText = literalExpression "pkgs.kubo";
-        description = lib.mdDoc "Which Kubo package to use.";
-      };
+      package = mkPackageOption pkgs "kubo" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/network-filesystems/litestream/default.nix b/nixos/modules/services/network-filesystems/litestream/default.nix
index 6e2ec1ccaa3c..afc38fcebcff 100644
--- a/nixos/modules/services/network-filesystems/litestream/default.nix
+++ b/nixos/modules/services/network-filesystems/litestream/default.nix
@@ -10,12 +10,7 @@ in
   options.services.litestream = {
     enable = mkEnableOption (lib.mdDoc "litestream");
 
-    package = mkOption {
-      description = lib.mdDoc "Package to use.";
-      default = pkgs.litestream;
-      defaultText = literalExpression "pkgs.litestream";
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "litestream" { };
 
     settings = mkOption {
       description = lib.mdDoc ''
diff --git a/nixos/modules/services/network-filesystems/openafs/server.nix b/nixos/modules/services/network-filesystems/openafs/server.nix
index fbaa7cfc1929..14bdf2f33865 100644
--- a/nixos/modules/services/network-filesystems/openafs/server.nix
+++ b/nixos/modules/services/network-filesystems/openafs/server.nix
@@ -5,7 +5,7 @@ with import ./lib.nix { inherit config lib pkgs; };
 
 let
   inherit (lib) concatStringsSep literalExpression mkIf mkOption mkEnableOption
-  optionalString types;
+  mkPackageOption optionalString types;
 
   bosConfig = pkgs.writeText "BosConfig" (''
     restrictmode 1
@@ -101,12 +101,7 @@ in {
         description = lib.mdDoc "Definition of all cell-local database server machines.";
       };
 
-      package = mkOption {
-        default = pkgs.openafs;
-        defaultText = literalExpression "pkgs.openafs";
-        type = types.package;
-        description = lib.mdDoc "OpenAFS package for the server binaries";
-      };
+      package = mkPackageOption pkgs "openafs" { };
 
       roles = {
         fileserver = {
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index 0b22302c0b6d..5d02eac8e9f1 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -120,14 +120,8 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.samba;
-        defaultText = literalExpression "pkgs.samba";
-        example = literalExpression "pkgs.samba4Full";
-        description = lib.mdDoc ''
-          Defines which package should be used for the samba server.
-        '';
+      package = mkPackageOption pkgs "samba" {
+        example = "samba4Full";
       };
 
       invalidUsers = mkOption {
diff --git a/nixos/modules/services/network-filesystems/tahoe.nix b/nixos/modules/services/network-filesystems/tahoe.nix
index 14c0a3d4725f..d016d4a38fb9 100644
--- a/nixos/modules/services/network-filesystems/tahoe.nix
+++ b/nixos/modules/services/network-filesystems/tahoe.nix
@@ -32,14 +32,7 @@ in
                 If specified, the port should be included.
               '';
             };
-            package = mkOption {
-              default = pkgs.tahoelafs;
-              defaultText = literalExpression "pkgs.tahoelafs";
-              type = types.package;
-              description = lib.mdDoc ''
-                The package to use for the Tahoe LAFS daemon.
-              '';
-            };
+            package = mkPackageOption pkgs "tahoelafs" { };
           };
         });
         description = lib.mdDoc ''
@@ -176,14 +169,7 @@ in
                 URL of the accounts server.
               '';
             };
-            package = mkOption {
-              default = pkgs.tahoelafs;
-              defaultText = literalExpression "pkgs.tahoelafs";
-              type = types.package;
-              description = lib.mdDoc ''
-                The package to use for the Tahoe LAFS daemon.
-              '';
-            };
+            package = mkPackageOption pkgs "tahoelafs" { };
           };
         });
         description = lib.mdDoc ''
diff --git a/nixos/modules/services/networking/asterisk.nix b/nixos/modules/services/networking/asterisk.nix
index 279927781edc..78a69efc86af 100644
--- a/nixos/modules/services/networking/asterisk.nix
+++ b/nixos/modules/services/networking/asterisk.nix
@@ -163,12 +163,7 @@ in
           Additional command line arguments to pass to Asterisk.
         '';
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.asterisk;
-        defaultText = literalExpression "pkgs.asterisk";
-        description = lib.mdDoc "The Asterisk package to use.";
-      };
+      package = mkPackageOption pkgs "asterisk" { };
     };
   };
 
diff --git a/nixos/modules/services/networking/avahi-daemon.nix b/nixos/modules/services/networking/avahi-daemon.nix
index bdbf9aad9acc..de51843ba6f9 100644
--- a/nixos/modules/services/networking/avahi-daemon.nix
+++ b/nixos/modules/services/networking/avahi-daemon.nix
@@ -56,14 +56,7 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.avahi;
-      defaultText = literalExpression "pkgs.avahi";
-      description = lib.mdDoc ''
-        The avahi package to use for running the daemon.
-      '';
-    };
+    package = mkPackageOption pkgs "avahi" { };
 
     hostName = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/networking/bee.nix b/nixos/modules/services/networking/bee.nix
index add9861ebfcd..962cfd30c3fe 100644
--- a/nixos/modules/services/networking/bee.nix
+++ b/nixos/modules/services/networking/bee.nix
@@ -17,12 +17,8 @@ in {
     services.bee = {
       enable = mkEnableOption (lib.mdDoc "Ethereum Swarm Bee");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.bee;
-        defaultText = literalExpression "pkgs.bee";
-        example = literalExpression "pkgs.bee-unstable";
-        description = lib.mdDoc "The package providing the bee binary for the service.";
+      package = mkPackageOption pkgs "bee" {
+        example = "bee-unstable";
       };
 
       settings = mkOption {
diff --git a/nixos/modules/services/networking/bind.nix b/nixos/modules/services/networking/bind.nix
index f1829747bb1e..da8633d5066f 100644
--- a/nixos/modules/services/networking/bind.nix
+++ b/nixos/modules/services/networking/bind.nix
@@ -118,12 +118,7 @@ in
       enable = mkEnableOption (lib.mdDoc "BIND domain name server");
 
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.bind;
-        defaultText = literalExpression "pkgs.bind";
-        description = lib.mdDoc "The BIND package to use.";
-      };
+      package = mkPackageOption pkgs "bind" { };
 
       cacheNetworks = mkOption {
         default = [ "127.0.0.0/24" ];
diff --git a/nixos/modules/services/networking/bird-lg.nix b/nixos/modules/services/networking/bird-lg.nix
index dc861dbfd11b..be9f4101e6ab 100644
--- a/nixos/modules/services/networking/bird-lg.nix
+++ b/nixos/modules/services/networking/bird-lg.nix
@@ -51,12 +51,7 @@ in
 {
   options = {
     services.bird-lg = {
-      package = mkOption {
-        type = types.package;
-        default = pkgs.bird-lg;
-        defaultText = literalExpression "pkgs.bird-lg";
-        description = lib.mdDoc "The Bird Looking Glass package to use.";
-      };
+      package = mkPackageOption pkgs "bird-lg" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/networking/birdwatcher.nix b/nixos/modules/services/networking/birdwatcher.nix
index a129b7a2b4cf..c8ebb2269764 100644
--- a/nixos/modules/services/networking/birdwatcher.nix
+++ b/nixos/modules/services/networking/birdwatcher.nix
@@ -8,12 +8,7 @@ in
 {
   options = {
     services.birdwatcher = {
-      package = mkOption {
-        type = types.package;
-        default = pkgs.birdwatcher;
-        defaultText = literalExpression "pkgs.birdwatcher";
-        description = lib.mdDoc "The Birdwatcher package to use.";
-      };
+      package = mkPackageOption pkgs "birdwatcher" { };
       enable = mkEnableOption (lib.mdDoc "Birdwatcher");
       flags = mkOption {
         default = [ ];
diff --git a/nixos/modules/services/networking/bitcoind.nix b/nixos/modules/services/networking/bitcoind.nix
index a48066b43b16..4512e666ba5b 100644
--- a/nixos/modules/services/networking/bitcoind.nix
+++ b/nixos/modules/services/networking/bitcoind.nix
@@ -36,12 +36,7 @@ let
 
       enable = mkEnableOption (lib.mdDoc "Bitcoin daemon");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.bitcoind;
-        defaultText = literalExpression "pkgs.bitcoind";
-        description = lib.mdDoc "The package providing bitcoin binaries.";
-      };
+      package = mkPackageOption pkgs "bitcoind" { };
 
       configFile = mkOption {
         type = types.nullOr types.path;
diff --git a/nixos/modules/services/networking/blockbook-frontend.nix b/nixos/modules/services/networking/blockbook-frontend.nix
index 46b26195d211..bf476d814140 100644
--- a/nixos/modules/services/networking/blockbook-frontend.nix
+++ b/nixos/modules/services/networking/blockbook-frontend.nix
@@ -12,12 +12,7 @@ let
 
       enable = mkEnableOption (lib.mdDoc "blockbook-frontend application");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.blockbook;
-        defaultText = literalExpression "pkgs.blockbook";
-        description = lib.mdDoc "Which blockbook package to use.";
-      };
+      package = mkPackageOption pkgs "blockbook" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/networking/cloudflared.nix b/nixos/modules/services/networking/cloudflared.nix
index b3f0e37d8e9e..80c60fdb8013 100644
--- a/nixos/modules/services/networking/cloudflared.nix
+++ b/nixos/modules/services/networking/cloudflared.nix
@@ -152,12 +152,7 @@ in
       description = lib.mdDoc "Group under which cloudflared runs.";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.cloudflared;
-      defaultText = "pkgs.cloudflared";
-      description = lib.mdDoc "The package to use for Cloudflared.";
-    };
+    package = mkPackageOption pkgs "cloudflared" { };
 
     tunnels = mkOption {
       description = lib.mdDoc ''
diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix
index 955463b9031e..1a0910fc9344 100644
--- a/nixos/modules/services/networking/consul.nix
+++ b/nixos/modules/services/networking/consul.nix
@@ -33,15 +33,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.consul;
-        defaultText = literalExpression "pkgs.consul";
-        description = lib.mdDoc ''
-          The package used for the Consul agent and CLI.
-        '';
-      };
-
+      package = mkPackageOption pkgs "consul" { };
 
       webUi = mkOption {
         type = types.bool;
@@ -128,12 +120,7 @@ in
       alerts = {
         enable = mkEnableOption (lib.mdDoc "consul-alerts");
 
-        package = mkOption {
-          description = lib.mdDoc "Package to use for consul-alerts.";
-          default = pkgs.consul-alerts;
-          defaultText = literalExpression "pkgs.consul-alerts";
-          type = types.package;
-        };
+        package = mkPackageOption pkgs "consul-alerts" { };
 
         listenAddr = mkOption {
           description = lib.mdDoc "Api listening address.";
diff --git a/nixos/modules/services/networking/coredns.nix b/nixos/modules/services/networking/coredns.nix
index f1fe7b2f1241..f6eec2f962dd 100644
--- a/nixos/modules/services/networking/coredns.nix
+++ b/nixos/modules/services/networking/coredns.nix
@@ -23,12 +23,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      default = pkgs.coredns;
-      defaultText = literalExpression "pkgs.coredns";
-      type = types.package;
-      description = lib.mdDoc "Coredns package to use.";
-    };
+    package = mkPackageOption pkgs "coredns" { };
 
     extraArgs = mkOption {
       default = [];
diff --git a/nixos/modules/services/networking/corerad.nix b/nixos/modules/services/networking/corerad.nix
index 0c6fb7a17cab..33ea2862174e 100644
--- a/nixos/modules/services/networking/corerad.nix
+++ b/nixos/modules/services/networking/corerad.nix
@@ -48,12 +48,7 @@ in {
       description = lib.mdDoc "Path to CoreRAD TOML configuration file.";
     };
 
-    package = mkOption {
-      default = pkgs.corerad;
-      defaultText = literalExpression "pkgs.corerad";
-      type = types.package;
-      description = lib.mdDoc "CoreRAD package to use.";
-    };
+    package = mkPackageOption pkgs "corerad" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix
index 3feafc3bb3bd..b10a3d9f21df 100644
--- a/nixos/modules/services/networking/ejabberd.nix
+++ b/nixos/modules/services/networking/ejabberd.nix
@@ -29,12 +29,7 @@ in {
         description = lib.mdDoc "Whether to enable ejabberd server";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.ejabberd;
-        defaultText = literalExpression "pkgs.ejabberd";
-        description = lib.mdDoc "ejabberd server package to use";
-      };
+      package = mkPackageOption pkgs "ejabberd" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/networking/epmd.nix b/nixos/modules/services/networking/epmd.nix
index 0bc8c71f4eaa..318e325944b5 100644
--- a/nixos/modules/services/networking/epmd.nix
+++ b/nixos/modules/services/networking/epmd.nix
@@ -17,15 +17,7 @@ in
         Erlang computations.
       '';
     };
-    package = mkOption {
-      type = types.package;
-      default = pkgs.erlang;
-      defaultText = literalExpression "pkgs.erlang";
-      description = lib.mdDoc ''
-        The Erlang package to use to get epmd binary. That way you can re-use
-        an Erlang runtime that is already installed for other purposes.
-      '';
-    };
+    package = mkPackageOption pkgs "erlang" { };
     listenStream = mkOption
       {
         type = types.str;
diff --git a/nixos/modules/services/networking/ferm.nix b/nixos/modules/services/networking/ferm.nix
index 09151eb0b544..5ebf7aacb4db 100644
--- a/nixos/modules/services/networking/ferm.nix
+++ b/nixos/modules/services/networking/ferm.nix
@@ -33,12 +33,7 @@ in {
         defaultText = literalMD "empty firewall, allows any traffic";
         type = types.lines;
       };
-      package = mkOption {
-        description = lib.mdDoc "The ferm package.";
-        type = types.package;
-        default = pkgs.ferm;
-        defaultText = literalExpression "pkgs.ferm";
-      };
+      package = mkPackageOption pkgs "ferm" { };
     };
   };
 
diff --git a/nixos/modules/services/networking/flannel.nix b/nixos/modules/services/networking/flannel.nix
index 6ed4f78ddc92..2c2b6dc58cce 100644
--- a/nixos/modules/services/networking/flannel.nix
+++ b/nixos/modules/services/networking/flannel.nix
@@ -16,12 +16,7 @@ in {
   options.services.flannel = {
     enable = mkEnableOption (lib.mdDoc "flannel");
 
-    package = mkOption {
-      description = lib.mdDoc "Package to use for flannel";
-      type = types.package;
-      default = pkgs.flannel;
-      defaultText = literalExpression "pkgs.flannel";
-    };
+    package = mkPackageOption pkgs "flannel" { };
 
     publicIp = mkOption {
       description = lib.mdDoc ''
diff --git a/nixos/modules/services/networking/ghostunnel.nix b/nixos/modules/services/networking/ghostunnel.nix
index 4902367e2a6a..d5e2ff19ce50 100644
--- a/nixos/modules/services/networking/ghostunnel.nix
+++ b/nixos/modules/services/networking/ghostunnel.nix
@@ -9,6 +9,7 @@ let
     mapAttrs'
     mkDefault
     mkEnableOption
+    mkPackageOption
     mkIf
     mkOption
     nameValuePair
@@ -215,12 +216,7 @@ in
   options = {
     services.ghostunnel.enable = mkEnableOption (lib.mdDoc "ghostunnel");
 
-    services.ghostunnel.package = mkOption {
-      description = lib.mdDoc "The ghostunnel package to use.";
-      type = types.package;
-      default = pkgs.ghostunnel;
-      defaultText = literalExpression "pkgs.ghostunnel";
-    };
+    services.ghostunnel.package = mkPackageOption pkgs "ghostunnel" { };
 
     services.ghostunnel.servers = mkOption {
       description = lib.mdDoc ''
diff --git a/nixos/modules/services/networking/gnunet.nix b/nixos/modules/services/networking/gnunet.nix
index fdb353fd3443..a235f1605e54 100644
--- a/nixos/modules/services/networking/gnunet.nix
+++ b/nixos/modules/services/networking/gnunet.nix
@@ -112,12 +112,8 @@ in
         };
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.gnunet;
-        defaultText = literalExpression "pkgs.gnunet";
-        description = lib.mdDoc "Overridable attribute of the gnunet package to use.";
-        example = literalExpression "pkgs.gnunet_git";
+      package = mkPackageOption pkgs "gnunet" {
+        example = "gnunet_git";
       };
 
       extraOptions = mkOption {
diff --git a/nixos/modules/services/networking/headscale.nix b/nixos/modules/services/networking/headscale.nix
index 03e6f86af53f..4224a0578cc3 100644
--- a/nixos/modules/services/networking/headscale.nix
+++ b/nixos/modules/services/networking/headscale.nix
@@ -17,14 +17,7 @@ in {
     services.headscale = {
       enable = mkEnableOption (lib.mdDoc "headscale, Open Source coordination server for Tailscale");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.headscale;
-        defaultText = literalExpression "pkgs.headscale";
-        description = lib.mdDoc ''
-          Which headscale package to use for the running server.
-        '';
-      };
+      package = mkPackageOption pkgs "headscale" { };
 
       user = mkOption {
         default = "headscale";
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
index 808e7b66d36e..8d9eff61488c 100644
--- a/nixos/modules/services/networking/i2pd.nix
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -244,14 +244,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.i2pd;
-        defaultText = literalExpression "pkgs.i2pd";
-        description = lib.mdDoc ''
-          i2pd package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "i2pd" { };
 
       logLevel = mkOption {
         type = types.enum ["debug" "info" "warn" "error"];
diff --git a/nixos/modules/services/networking/icecream/daemon.nix b/nixos/modules/services/networking/icecream/daemon.nix
index fdd7a139c2fa..48363cc22c36 100644
--- a/nixos/modules/services/networking/icecream/daemon.nix
+++ b/nixos/modules/services/networking/icecream/daemon.nix
@@ -99,12 +99,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        default = pkgs.icecream;
-        defaultText = literalExpression "pkgs.icecream";
-        type = types.package;
-        description = lib.mdDoc "Icecream package to use.";
-      };
+      package = mkPackageOption pkgs "icecream" { };
 
       extraArgs = mkOption {
         type = types.listOf types.str;
diff --git a/nixos/modules/services/networking/icecream/scheduler.nix b/nixos/modules/services/networking/icecream/scheduler.nix
index 33aee1bb19cc..2d53282ba88f 100644
--- a/nixos/modules/services/networking/icecream/scheduler.nix
+++ b/nixos/modules/services/networking/icecream/scheduler.nix
@@ -54,12 +54,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        default = pkgs.icecream;
-        defaultText = literalExpression "pkgs.icecream";
-        type = types.package;
-        description = lib.mdDoc "Icecream package to use.";
-      };
+      package = mkPackageOption pkgs "icecream" { };
 
       extraArgs = mkOption {
         type = types.listOf types.str;
diff --git a/nixos/modules/services/networking/iscsi/initiator.nix b/nixos/modules/services/networking/iscsi/initiator.nix
index 6c30f89b7968..2d802d8cfc70 100644
--- a/nixos/modules/services/networking/iscsi/initiator.nix
+++ b/nixos/modules/services/networking/iscsi/initiator.nix
@@ -19,12 +19,7 @@ in
       description = lib.mdDoc "Name of this iscsi initiator";
       example = "iqn.2020-08.org.linux-iscsi.initiatorhost:example";
     };
-    package = mkOption {
-      type = package;
-      description = lib.mdDoc "openiscsi package to use";
-      default = pkgs.openiscsi;
-      defaultText = literalExpression "pkgs.openiscsi";
-    };
+    package = mkPackageOption pkgs "openiscsi" { };
 
     extraConfig = mkOption {
       type = str;
diff --git a/nixos/modules/services/networking/iwd.nix b/nixos/modules/services/networking/iwd.nix
index 993a603c1ed5..b74f5d0bec9b 100644
--- a/nixos/modules/services/networking/iwd.nix
+++ b/nixos/modules/services/networking/iwd.nix
@@ -2,7 +2,7 @@
 
 let
   inherit (lib)
-    mkEnableOption mkIf mkOption types
+    mkEnableOption mkPackageOption mkIf mkOption types
     recursiveUpdate;
 
   cfg = config.networking.wireless.iwd;
@@ -19,14 +19,7 @@ in
   options.networking.wireless.iwd = {
     enable = mkEnableOption (lib.mdDoc "iwd");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.iwd;
-      defaultText = lib.literalExpression "pkgs.iwd";
-      description = lib.mdDoc ''
-        The iwd package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "iwd" { };
 
     settings = mkOption {
       type = ini.type;
diff --git a/nixos/modules/services/networking/knot.nix b/nixos/modules/services/networking/knot.nix
index 4f6ac945cf97..d4bd81629c97 100644
--- a/nixos/modules/services/networking/knot.nix
+++ b/nixos/modules/services/networking/knot.nix
@@ -182,14 +182,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.knot-dns;
-        defaultText = literalExpression "pkgs.knot-dns";
-        description = lib.mdDoc ''
-          Which Knot DNS package to use
-        '';
-      };
+      package = mkPackageOption pkgs "knot-dns" { };
     };
   };
   imports = [
diff --git a/nixos/modules/services/networking/kresd.nix b/nixos/modules/services/networking/kresd.nix
index 3ad757133a60..0c7363e564dc 100644
--- a/nixos/modules/services/networking/kresd.nix
+++ b/nixos/modules/services/networking/kresd.nix
@@ -57,14 +57,8 @@ in {
         and give commands interactively to kresd@1.service.
       '';
     };
-    package = mkOption {
-      type = types.package;
-      description = lib.mdDoc ''
-        knot-resolver package to use.
-      '';
-      default = pkgs.knot-resolver;
-      defaultText = literalExpression "pkgs.knot-resolver";
-      example = literalExpression "pkgs.knot-resolver.override { extraFeatures = true; }";
+    package = mkPackageOption pkgs "knot-resolver" {
+      example = "knot-resolver.override { extraFeatures = true; }";
     };
     extraConfig = mkOption {
       type = types.lines;
diff --git a/nixos/modules/services/networking/lambdabot.nix b/nixos/modules/services/networking/lambdabot.nix
index 8609bc971962..01914097ad72 100644
--- a/nixos/modules/services/networking/lambdabot.nix
+++ b/nixos/modules/services/networking/lambdabot.nix
@@ -24,12 +24,7 @@ in
         description = lib.mdDoc "Enable the Lambdabot IRC bot";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.lambdabot;
-        defaultText = literalExpression "pkgs.lambdabot";
-        description = lib.mdDoc "Used lambdabot package";
-      };
+      package = mkPackageOption pkgs "lambdabot" { };
 
       script = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/networking/lokinet.nix b/nixos/modules/services/networking/lokinet.nix
index f6bc314ed260..8f64d3f0119f 100644
--- a/nixos/modules/services/networking/lokinet.nix
+++ b/nixos/modules/services/networking/lokinet.nix
@@ -9,12 +9,7 @@ in with lib; {
   options.services.lokinet = {
     enable = mkEnableOption (lib.mdDoc "Lokinet daemon");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.lokinet;
-      defaultText = literalExpression "pkgs.lokinet";
-      description = lib.mdDoc "Lokinet package to use.";
-    };
+    package = mkPackageOption pkgs "lokinet" { };
 
     useLocally = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/networking/miredo.nix b/nixos/modules/services/networking/miredo.nix
index d15a55b4d7d6..0c43839c15ab 100644
--- a/nixos/modules/services/networking/miredo.nix
+++ b/nixos/modules/services/networking/miredo.nix
@@ -22,14 +22,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "the Miredo IPv6 tunneling service");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.miredo;
-        defaultText = literalExpression "pkgs.miredo";
-        description = lib.mdDoc ''
-          The package to use for the miredo daemon's binary.
-        '';
-      };
+      package = mkPackageOption pkgs "miredo" { };
 
       serverAddress = mkOption {
         default = "teredo.remlab.net";
diff --git a/nixos/modules/services/networking/morty.nix b/nixos/modules/services/networking/morty.nix
index 72514764a7c6..6954596addfd 100644
--- a/nixos/modules/services/networking/morty.nix
+++ b/nixos/modules/services/networking/morty.nix
@@ -42,12 +42,7 @@ in
         description = lib.mdDoc "Request timeout in seconds.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.morty;
-        defaultText = literalExpression "pkgs.morty";
-        description = lib.mdDoc "morty package to use.";
-      };
+      package = mkPackageOption pkgs "morty" { };
 
       port = mkOption {
         type = types.port;
diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix
index c53d86c0babc..f2b158b98942 100644
--- a/nixos/modules/services/networking/mosquitto.nix
+++ b/nixos/modules/services/networking/mosquitto.nix
@@ -482,14 +482,7 @@ let
   globalOptions = with types; {
     enable = mkEnableOption (lib.mdDoc "the MQTT Mosquitto broker");
 
-    package = mkOption {
-      type = package;
-      default = pkgs.mosquitto;
-      defaultText = literalExpression "pkgs.mosquitto";
-      description = lib.mdDoc ''
-        Mosquitto package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "mosquitto" { };
 
     bridges = mkOption {
       type = attrsOf bridgeOptions;
diff --git a/nixos/modules/services/networking/mtr-exporter.nix b/nixos/modules/services/networking/mtr-exporter.nix
index af694c3e736b..38bc0401a7e6 100644
--- a/nixos/modules/services/networking/mtr-exporter.nix
+++ b/nixos/modules/services/networking/mtr-exporter.nix
@@ -5,7 +5,7 @@ let
     maintainers types literalExpression
     escapeShellArg escapeShellArgs
     mkEnableOption mkOption mkRemovedOptionModule mkIf mdDoc
-    optionalString concatMapStrings concatStringsSep;
+    mkPackageOption optionalString concatMapStrings concatStringsSep;
 
   cfg = config.services.mtr-exporter;
 
@@ -44,19 +44,9 @@ in {
           '';
         };
 
-        package = mkOption {
-          type = types.package;
-          default = pkgs.mtr-exporter;
-          defaultText = literalExpression "pkgs.mtr-exporter";
-          description = mdDoc "The MTR exporter package to use.";
-        };
+        package = mkPackageOption pkgs "mtr-exporter" { };
 
-        mtrPackage = mkOption {
-          type = types.package;
-          default = pkgs.mtr;
-          defaultText = literalExpression "pkgs.mtr";
-          description = mdDoc "The MTR package to use.";
-        };
+        mtrPackage = mkPackageOption pkgs "mtr" { };
 
         jobs = mkOption {
           description = mdDoc "List of MTR jobs. Will be added to /etc/mtr-exporter.conf";
diff --git a/nixos/modules/services/networking/mullvad-vpn.nix b/nixos/modules/services/networking/mullvad-vpn.nix
index 8c7d5237971f..446c71f40764 100644
--- a/nixos/modules/services/networking/mullvad-vpn.nix
+++ b/nixos/modules/services/networking/mullvad-vpn.nix
@@ -23,12 +23,10 @@ with lib;
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.mullvad;
-      defaultText = literalExpression "pkgs.mullvad";
-      description = lib.mdDoc ''
-        The Mullvad package to use. `pkgs.mullvad` only provides the CLI tool, `pkgs.mullvad-vpn` provides both the CLI and the GUI.
+    package = mkPackageOption pkgs "mullvad" {
+      example = "mullvad-vpn";
+      extraDescription = ''
+        `pkgs.mullvad` only provides the CLI tool, `pkgs.mullvad-vpn` provides both the CLI and the GUI.
       '';
     };
   };
diff --git a/nixos/modules/services/networking/multipath.nix b/nixos/modules/services/networking/multipath.nix
index 9099cbe0cd32..42ffc3c88426 100644
--- a/nixos/modules/services/networking/multipath.nix
+++ b/nixos/modules/services/networking/multipath.nix
@@ -24,12 +24,7 @@ in {
 
     enable = mkEnableOption (lib.mdDoc "the device mapper multipath (DM-MP) daemon");
 
-    package = mkOption {
-      type = package;
-      description = lib.mdDoc "multipath-tools package to use";
-      default = pkgs.multipath-tools;
-      defaultText = lib.literalExpression "pkgs.multipath-tools";
-    };
+    package = mkPackageOption pkgs "multipath-tools" { };
 
     devices = mkOption {
       default = [ ];
diff --git a/nixos/modules/services/networking/murmur.nix b/nixos/modules/services/networking/murmur.nix
index 20c2eff11e62..0cd80e134ace 100644
--- a/nixos/modules/services/networking/murmur.nix
+++ b/nixos/modules/services/networking/murmur.nix
@@ -119,12 +119,7 @@ in
         description = lib.mdDoc "Host to bind to. Defaults binding on all addresses.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.murmur;
-        defaultText = literalExpression "pkgs.murmur";
-        description = lib.mdDoc "Overridable attribute of the murmur package to use.";
-      };
+      package = mkPackageOption pkgs "murmur" { };
 
       password = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/networking/mxisd.nix b/nixos/modules/services/networking/mxisd.nix
index 528a51c1f3af..47d2b16a1501 100644
--- a/nixos/modules/services/networking/mxisd.nix
+++ b/nixos/modules/services/networking/mxisd.nix
@@ -39,12 +39,7 @@ in {
     services.mxisd = {
       enable = mkEnableOption (lib.mdDoc "matrix federated identity server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.ma1sd;
-        defaultText = literalExpression "pkgs.ma1sd";
-        description = lib.mdDoc "The mxisd/ma1sd package to use";
-      };
+      package = mkPackageOption pkgs "ma1sd" { };
 
       environmentFile = mkOption {
         type = types.nullOr types.str;
diff --git a/nixos/modules/services/networking/nebula.nix b/nixos/modules/services/networking/nebula.nix
index e1a8c6740f57..b9ebbfbd9a29 100644
--- a/nixos/modules/services/networking/nebula.nix
+++ b/nixos/modules/services/networking/nebula.nix
@@ -27,12 +27,7 @@ in
               description = lib.mdDoc "Enable or disable this network.";
             };
 
-            package = mkOption {
-              type = types.package;
-              default = pkgs.nebula;
-              defaultText = literalExpression "pkgs.nebula";
-              description = lib.mdDoc "Nebula derivation to use.";
-            };
+            package = mkPackageOption pkgs "nebula" { };
 
             ca = mkOption {
               type = types.path;
diff --git a/nixos/modules/services/networking/netbird.nix b/nixos/modules/services/networking/netbird.nix
index 647c0ce3e6d1..4b0bd63e9dbc 100644
--- a/nixos/modules/services/networking/netbird.nix
+++ b/nixos/modules/services/networking/netbird.nix
@@ -11,12 +11,7 @@ in {
 
   options.services.netbird = {
     enable = mkEnableOption (lib.mdDoc "Netbird daemon");
-    package = mkOption {
-      type = types.package;
-      default = pkgs.netbird;
-      defaultText = literalExpression "pkgs.netbird";
-      description = lib.mdDoc "The package to use for netbird";
-    };
+    package = mkPackageOption pkgs "netbird" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/networking/ngircd.nix b/nixos/modules/services/networking/ngircd.nix
index 5e721f5aa625..a2fff78fdff8 100644
--- a/nixos/modules/services/networking/ngircd.nix
+++ b/nixos/modules/services/networking/ngircd.nix
@@ -28,14 +28,7 @@ in {
         type = types.lines;
       };
 
-      package = mkOption {
-        description = lib.mdDoc "The ngircd package.";
-
-        type = types.package;
-
-        default = pkgs.ngircd;
-        defaultText = literalExpression "pkgs.ngircd";
-      };
+      package = mkPackageOption pkgs "ngircd" { };
     };
   };
 
diff --git a/nixos/modules/services/networking/nix-serve.nix b/nixos/modules/services/networking/nix-serve.nix
index 86bb603e1271..a0c0be2ff254 100644
--- a/nixos/modules/services/networking/nix-serve.nix
+++ b/nixos/modules/services/networking/nix-serve.nix
@@ -26,14 +26,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.nix-serve;
-        defaultText = literalExpression "pkgs.nix-serve";
-        description = lib.mdDoc ''
-          nix-serve package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "nix-serve" { };
 
       openFirewall = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/networking/nomad.nix b/nixos/modules/services/networking/nomad.nix
index b1e51195247a..8cb0264648de 100644
--- a/nixos/modules/services/networking/nomad.nix
+++ b/nixos/modules/services/networking/nomad.nix
@@ -10,14 +10,7 @@ in
     services.nomad = {
       enable = mkEnableOption (lib.mdDoc "Nomad, a distributed, highly available, datacenter-aware scheduler");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.nomad;
-        defaultText = literalExpression "pkgs.nomad";
-        description = lib.mdDoc ''
-          The package used for the Nomad agent and CLI.
-        '';
-      };
+      package = mkPackageOption pkgs "nomad" { };
 
       extraPackages = mkOption {
         type = types.listOf types.package;
diff --git a/nixos/modules/services/networking/ntp/chrony.nix b/nixos/modules/services/networking/ntp/chrony.nix
index 3f10145033c5..b56bea4e134f 100644
--- a/nixos/modules/services/networking/ntp/chrony.nix
+++ b/nixos/modules/services/networking/ntp/chrony.nix
@@ -47,14 +47,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.chrony;
-        defaultText = literalExpression "pkgs.chrony";
-        description = lib.mdDoc ''
-          Which chrony package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "chrony" { };
 
       servers = mkOption {
         default = config.networking.timeServers;
diff --git a/nixos/modules/services/networking/pleroma.nix b/nixos/modules/services/networking/pleroma.nix
index 89e64d36c8a0..db0a61b83469 100644
--- a/nixos/modules/services/networking/pleroma.nix
+++ b/nixos/modules/services/networking/pleroma.nix
@@ -6,12 +6,7 @@ in {
     services.pleroma = with lib; {
       enable = mkEnableOption (lib.mdDoc "pleroma");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.pleroma;
-        defaultText = literalExpression "pkgs.pleroma";
-        description = lib.mdDoc "Pleroma package to use.";
-      };
+      package = mkPackageOption pkgs "pleroma" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/networking/pppd.nix b/nixos/modules/services/networking/pppd.nix
index 75fc04c67571..855b5358f47f 100644
--- a/nixos/modules/services/networking/pppd.nix
+++ b/nixos/modules/services/networking/pppd.nix
@@ -14,12 +14,7 @@ in
     services.pppd = {
       enable = mkEnableOption (lib.mdDoc "pppd");
 
-      package = mkOption {
-        default = pkgs.ppp;
-        defaultText = literalExpression "pkgs.ppp";
-        type = types.package;
-        description = lib.mdDoc "pppd package to use.";
-      };
+      package = mkPackageOption pkgs "ppp" { };
 
       peers = mkOption {
         default = {};
diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix
index 038d574bd878..2952df2a1099 100644
--- a/nixos/modules/services/networking/prosody.nix
+++ b/nixos/modules/services/networking/prosody.nix
@@ -496,12 +496,8 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        description = lib.mdDoc "Prosody package to use";
-        default = pkgs.prosody;
-        defaultText = literalExpression "pkgs.prosody";
-        example = literalExpression ''
+      package = mkPackageOption pkgs "prosody" {
+        example = ''
           pkgs.prosody.override {
             withExtraLibs = [ pkgs.luaPackages.lpty ];
             withCommunityModules = [ "auth_external" ];
diff --git a/nixos/modules/services/networking/quassel.nix b/nixos/modules/services/networking/quassel.nix
index a074023b5ee4..4294d67fffd3 100644
--- a/nixos/modules/services/networking/quassel.nix
+++ b/nixos/modules/services/networking/quassel.nix
@@ -35,14 +35,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.quasselDaemon;
-        defaultText = literalExpression "pkgs.quasselDaemon";
-        description = lib.mdDoc ''
-          The package of the quassel daemon.
-        '';
-      };
+      package = mkPackageOption pkgs "quasselDaemon" { };
 
       interfaces = mkOption {
         type = types.listOf types.str;
diff --git a/nixos/modules/services/networking/radvd.nix b/nixos/modules/services/networking/radvd.nix
index 72590eda4ee6..57aa21287050 100644
--- a/nixos/modules/services/networking/radvd.nix
+++ b/nixos/modules/services/networking/radvd.nix
@@ -32,14 +32,7 @@ in
         '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.radvd;
-      defaultText = literalExpression "pkgs.radvd";
-      description = lib.mdDoc ''
-        The RADVD package to use for the RADVD service.
-      '';
-    };
+    package = mkPackageOption pkgs "radvd" { };
 
     config = mkOption {
       type = types.lines;
diff --git a/nixos/modules/services/networking/routedns.nix b/nixos/modules/services/networking/routedns.nix
index 2a29a06700ce..126539702438 100644
--- a/nixos/modules/services/networking/routedns.nix
+++ b/nixos/modules/services/networking/routedns.nix
@@ -52,12 +52,7 @@ in
       description = lib.mdDoc "Path to RouteDNS TOML configuration file.";
     };
 
-    package = mkOption {
-      default = pkgs.routedns;
-      defaultText = literalExpression "pkgs.routedns";
-      type = types.package;
-      description = lib.mdDoc "RouteDNS package to use.";
-    };
+    package = mkPackageOption pkgs "routedns" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/networking/sabnzbd.nix b/nixos/modules/services/networking/sabnzbd.nix
index 8f3545df8995..cff2622b38e9 100644
--- a/nixos/modules/services/networking/sabnzbd.nix
+++ b/nixos/modules/services/networking/sabnzbd.nix
@@ -17,12 +17,7 @@ in
     services.sabnzbd = {
       enable = mkEnableOption (lib.mdDoc "the sabnzbd server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.sabnzbd;
-        defaultText = lib.literalExpression "pkgs.sabnzbd";
-        description = lib.mdDoc "The sabnzbd executable package run by the service.";
-      };
+      package = mkPackageOption pkgs "sabnzbd" { };
 
       configFile = mkOption {
         type = types.path;
diff --git a/nixos/modules/services/networking/seafile.nix b/nixos/modules/services/networking/seafile.nix
index b07d51b9b49a..9caabc60c78f 100644
--- a/nixos/modules/services/networking/seafile.nix
+++ b/nixos/modules/services/networking/seafile.nix
@@ -121,12 +121,7 @@ in {
       '';
     };
 
-    seafilePackage = mkOption {
-      type = types.package;
-      description = lib.mdDoc "Which package to use for the seafile server.";
-      default = pkgs.seafile-server;
-      defaultText = literalExpression "pkgs.seafile-server";
-    };
+    seafilePackage = mkPackageOption pkgs "seafile-server" { };
 
     seahubExtraConf = mkOption {
       default = "";
diff --git a/nixos/modules/services/networking/searx.nix b/nixos/modules/services/networking/searx.nix
index 8054f01d705f..938d585e3179 100644
--- a/nixos/modules/services/networking/searx.nix
+++ b/nixos/modules/services/networking/searx.nix
@@ -143,12 +143,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.searxng;
-        defaultText = literalExpression "pkgs.searxng";
-        description = lib.mdDoc "searx package to use.";
-      };
+      package = mkPackageOption pkgs "searxng" { };
 
       runInUwsgi = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix
index 84cf6b0deac1..0514bff2767e 100644
--- a/nixos/modules/services/networking/skydns.nix
+++ b/nixos/modules/services/networking/skydns.nix
@@ -55,12 +55,7 @@ in {
       example = ["8.8.8.8:53" "8.8.4.4:53"];
     };
 
-    package = mkOption {
-      default = pkgs.skydns;
-      defaultText = literalExpression "pkgs.skydns";
-      type = types.package;
-      description = lib.mdDoc "Skydns package to use.";
-    };
+    package = mkPackageOption pkgs "skydns" { };
 
     extraConfig = mkOption {
       default = {};
diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix
index c7aec7d9489f..4ecf411c7496 100644
--- a/nixos/modules/services/networking/smokeping.nix
+++ b/nixos/modules/services/networking/smokeping.nix
@@ -165,12 +165,7 @@ in
         example = "no-reply@yourdomain.com";
         description = lib.mdDoc "Email contact for owner";
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.smokeping;
-        defaultText = literalExpression "pkgs.smokeping";
-        description = lib.mdDoc "Specify a custom smokeping package";
-      };
+      package = mkPackageOption pkgs "smokeping" { };
       host = mkOption {
         type = types.nullOr types.str;
         default = "localhost";
diff --git a/nixos/modules/services/networking/softether.nix b/nixos/modules/services/networking/softether.nix
index c8e888eafcc2..234832ea0c0f 100644
--- a/nixos/modules/services/networking/softether.nix
+++ b/nixos/modules/services/networking/softether.nix
@@ -18,14 +18,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "SoftEther VPN services");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.softether;
-        defaultText = literalExpression "pkgs.softether";
-        description = lib.mdDoc ''
-          softether derivation to use.
-        '';
-      };
+      package = mkPackageOption pkgs "softether" { };
 
       vpnserver.enable = mkEnableOption (lib.mdDoc "SoftEther VPN Server");
 
diff --git a/nixos/modules/services/networking/spacecookie.nix b/nixos/modules/services/networking/spacecookie.nix
index b2956edfcb7f..745c942ba60b 100644
--- a/nixos/modules/services/networking/spacecookie.nix
+++ b/nixos/modules/services/networking/spacecookie.nix
@@ -27,15 +27,8 @@ in {
 
       enable = mkEnableOption (lib.mdDoc "spacecookie");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.spacecookie;
-        defaultText = literalExpression "pkgs.spacecookie";
-        example = literalExpression "pkgs.haskellPackages.spacecookie";
-        description = lib.mdDoc ''
-          The spacecookie derivation to use. This can be used to
-          override the used package or to use another version.
-        '';
+      package = mkPackageOption pkgs "spacecookie" {
+        example = "haskellPackages.spacecookie";
       };
 
       openFirewall = mkOption {
diff --git a/nixos/modules/services/networking/squid.nix b/nixos/modules/services/networking/squid.nix
index f93bcf19f2b3..68f4dc3d6dc1 100644
--- a/nixos/modules/services/networking/squid.nix
+++ b/nixos/modules/services/networking/squid.nix
@@ -111,12 +111,7 @@ in
         description = lib.mdDoc "Whether to run squid web proxy.";
       };
 
-      package = mkOption {
-        default = pkgs.squid;
-        defaultText = literalExpression "pkgs.squid";
-        type = types.package;
-        description = lib.mdDoc "Squid package to use.";
-      };
+      package = mkPackageOption pkgs "squid" { };
 
       proxyAddress = mkOption {
         type = types.nullOr types.str;
diff --git a/nixos/modules/services/networking/strongswan-swanctl/module.nix b/nixos/modules/services/networking/strongswan-swanctl/module.nix
index bfea89969728..c8832ed4defb 100644
--- a/nixos/modules/services/networking/strongswan-swanctl/module.nix
+++ b/nixos/modules/services/networking/strongswan-swanctl/module.nix
@@ -10,14 +10,7 @@ in  {
   options.services.strongswan-swanctl = {
     enable = mkEnableOption (lib.mdDoc "strongswan-swanctl service");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.strongswan;
-      defaultText = literalExpression "pkgs.strongswan";
-      description = lib.mdDoc ''
-        The strongswan derivation to use.
-      '';
-    };
+    package = mkPackageOption pkgs "strongswan" { };
 
     strongswan.extraConfig = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index 6d9af6141f12..99d4d9eeffcc 100644
--- a/nixos/modules/services/networking/syncthing.nix
+++ b/nixos/modules/services/networking/syncthing.nix
@@ -583,14 +583,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.syncthing;
-        defaultText = literalExpression "pkgs.syncthing";
-        description = lib.mdDoc ''
-          The Syncthing package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "syncthing" { };
     };
   };
 
diff --git a/nixos/modules/services/networking/tayga.nix b/nixos/modules/services/networking/tayga.nix
index 299ae2777f7c..63423bf02922 100644
--- a/nixos/modules/services/networking/tayga.nix
+++ b/nixos/modules/services/networking/tayga.nix
@@ -64,12 +64,7 @@ in
     services.tayga = {
       enable = mkEnableOption (lib.mdDoc "Tayga");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.tayga;
-        defaultText = lib.literalMD "pkgs.tayga";
-        description = lib.mdDoc "This option specifies the TAYGA package to use.";
-      };
+      package = mkPackageOption pkgs "tayga" { };
 
       ipv4 = mkOption {
         type = types.submodule (versionOpts 4);
diff --git a/nixos/modules/services/networking/teleport.nix b/nixos/modules/services/networking/teleport.nix
index 399af711c0e1..add6b47315b1 100644
--- a/nixos/modules/services/networking/teleport.nix
+++ b/nixos/modules/services/networking/teleport.nix
@@ -11,12 +11,8 @@ in
     services.teleport = with lib.types; {
       enable = mkEnableOption (lib.mdDoc "the Teleport service");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.teleport;
-        defaultText = lib.literalMD "pkgs.teleport";
-        example = lib.literalMD "pkgs.teleport_11";
-        description = lib.mdDoc "The teleport package to use";
+      package = mkPackageOption pkgs "teleport" {
+        example = "teleport_11";
       };
 
       settings = mkOption {
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index 7db83e6a584b..eb769f53901c 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -279,14 +279,7 @@ in
               '';
             };
 
-            package = mkOption {
-              type = types.package;
-              default = pkgs.tinc_pre;
-              defaultText = literalExpression "pkgs.tinc_pre";
-              description = lib.mdDoc ''
-                The package to use for the tinc daemon's binary.
-              '';
-            };
+            package = mkPackageOption pkgs "tinc_pre" { };
 
             chroot = mkOption {
               default = false;
diff --git a/nixos/modules/services/networking/tmate-ssh-server.nix b/nixos/modules/services/networking/tmate-ssh-server.nix
index 91cb79ae2479..6bee2721f9a7 100644
--- a/nixos/modules/services/networking/tmate-ssh-server.nix
+++ b/nixos/modules/services/networking/tmate-ssh-server.nix
@@ -18,12 +18,7 @@ in
   options.services.tmate-ssh-server = {
     enable = mkEnableOption (mdDoc "tmate ssh server");
 
-    package = mkOption {
-      type = types.package;
-      description = mdDoc "The package containing tmate-ssh-server";
-      defaultText = literalExpression "pkgs.tmate-ssh-server";
-      default = pkgs.tmate-ssh-server;
-    };
+    package = mkPackageOption pkgs "tmate-ssh-server" { };
 
     host = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/networking/trickster.nix b/nixos/modules/services/networking/trickster.nix
index 0b696e412b4d..4b920ec446e0 100644
--- a/nixos/modules/services/networking/trickster.nix
+++ b/nixos/modules/services/networking/trickster.nix
@@ -20,14 +20,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.trickster;
-        defaultText = literalExpression "pkgs.trickster";
-        description = lib.mdDoc ''
-          Package that should be used for trickster.
-        '';
-      };
+      package = mkPackageOption pkgs "trickster" { };
 
       configFile = mkOption {
         type = types.nullOr types.path;
diff --git a/nixos/modules/services/networking/trust-dns.nix b/nixos/modules/services/networking/trust-dns.nix
index 758e33f16d38..47020341024b 100644
--- a/nixos/modules/services/networking/trust-dns.nix
+++ b/nixos/modules/services/networking/trust-dns.nix
@@ -48,13 +48,11 @@ in
   options = {
     services.trust-dns = with lib; {
       enable = mkEnableOption (lib.mdDoc "trust-dns");
-      package = mkOption {
-        type = types.package;
-        default = pkgs.trust-dns;
-        defaultText = "pkgs.trust-dns";
-        description = mdDoc ''
-          Trust-dns package to use.
-          The package must provide `meta.mainProgram` which names the server binary; any other utilities (client, resolver) are not needed.
+      package = mkPackageOption pkgs "trust-dns" {
+        extraDescription = ''
+          ::: {.note}
+          The package must provide `meta.mainProgram` which names the server binayr; any other utilities (client, resolver) are not needed.
+          :::
         '';
       };
       quiet = mkOption {
diff --git a/nixos/modules/services/networking/ucarp.nix b/nixos/modules/services/networking/ucarp.nix
index 1214cec63f54..56799fe00ade 100644
--- a/nixos/modules/services/networking/ucarp.nix
+++ b/nixos/modules/services/networking/ucarp.nix
@@ -143,16 +143,11 @@ in {
       default = null;
     };
 
-    package = mkOption {
-      type = types.package;
-      description = lib.mdDoc ''
-        Package that should be used for ucarp.
-
+    package = mkPackageOption pkgs "ucarp" {
+      extraDescription = ''
         Please note that the default package, pkgs.ucarp, has not received any
         upstream updates for a long time and can be considered as unmaintained.
       '';
-      default = pkgs.ucarp;
-      defaultText = literalExpression "pkgs.ucarp";
     };
   };
 
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index b6579af10a79..616b32f11797 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -42,12 +42,7 @@ in {
 
       enable = mkEnableOption (lib.mdDoc "Unbound domain name server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.unbound-with-systemd;
-        defaultText = literalExpression "pkgs.unbound-with-systemd";
-        description = lib.mdDoc "The unbound package to use";
-      };
+      package = mkPackageOption pkgs "unbound-with-systemd" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix
index 537a4db95ca7..8eb29f2bcdb6 100644
--- a/nixos/modules/services/networking/unifi.nix
+++ b/nixos/modules/services/networking/unifi.nix
@@ -36,21 +36,14 @@ in
       '';
     };
 
-    services.unifi.unifiPackage = lib.mkOption {
-      type = lib.types.package;
-      default = pkgs.unifi5;
-      defaultText = lib.literalExpression "pkgs.unifi5";
-      description = lib.mdDoc ''
-        The unifi package to use.
-      '';
-    };
-
-    services.unifi.mongodbPackage = lib.mkOption {
-      type = lib.types.package;
-      default = pkgs.mongodb-4_4;
-      defaultText = lib.literalExpression "pkgs.mongodb";
-      description = lib.mdDoc ''
-        The mongodb package to use. Please note: unifi7 officially only supports mongodb up until 3.6 but works with 4.4.
+    services.unifi.unifiPackage = lib.mkPackageOption pkgs "unifi5" { };
+
+    services.unifi.mongodbPackage = lib.mkPackageOption pkgs "mongodb" {
+      default = "mongodb-4_4";
+      extraDescription = ''
+        ::: {.note}
+        unifi7 officially only supports mongodb up until 3.6 but works with 4.4.
+        :::
       '';
     };
 
diff --git a/nixos/modules/services/networking/v2ray.nix b/nixos/modules/services/networking/v2ray.nix
index ba2aa5bc1de7..3e1895fbe20c 100644
--- a/nixos/modules/services/networking/v2ray.nix
+++ b/nixos/modules/services/networking/v2ray.nix
@@ -16,14 +16,7 @@ with lib;
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.v2ray;
-        defaultText = literalExpression "pkgs.v2ray";
-        description = lib.mdDoc ''
-          Which v2ray package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "v2ray" { };
 
       configFile = mkOption {
         type = types.nullOr types.str;
diff --git a/nixos/modules/services/networking/xandikos.nix b/nixos/modules/services/networking/xandikos.nix
index 6d1ddc74c719..147f07ac546d 100644
--- a/nixos/modules/services/networking/xandikos.nix
+++ b/nixos/modules/services/networking/xandikos.nix
@@ -11,12 +11,7 @@ in
     services.xandikos = {
       enable = mkEnableOption (lib.mdDoc "Xandikos CalDAV and CardDAV server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.xandikos;
-        defaultText = literalExpression "pkgs.xandikos";
-        description = lib.mdDoc "The Xandikos package to use.";
-      };
+      package = mkPackageOption pkgs "xandikos" { };
 
       address = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/networking/xray.nix b/nixos/modules/services/networking/xray.nix
index 83655a2f88ef..56c7887b3308 100644
--- a/nixos/modules/services/networking/xray.nix
+++ b/nixos/modules/services/networking/xray.nix
@@ -16,14 +16,7 @@ with lib;
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.xray;
-        defaultText = literalExpression "pkgs.xray";
-        description = lib.mdDoc ''
-          Which xray package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "xray" { };
 
       settingsFile = mkOption {
         type = types.nullOr types.path;
diff --git a/nixos/modules/services/networking/xrdp.nix b/nixos/modules/services/networking/xrdp.nix
index 218b440aab3c..3b674840b936 100644
--- a/nixos/modules/services/networking/xrdp.nix
+++ b/nixos/modules/services/networking/xrdp.nix
@@ -44,14 +44,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "xrdp, the Remote Desktop Protocol server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.xrdp;
-        defaultText = literalExpression "pkgs.xrdp";
-        description = lib.mdDoc ''
-          The package to use for the xrdp daemon's binary.
-        '';
-      };
+      package = mkPackageOption pkgs "xrdp" { };
 
       port = mkOption {
         type = types.port;
diff --git a/nixos/modules/services/networking/yggdrasil.nix b/nixos/modules/services/networking/yggdrasil.nix
index 56d81fb04013..514753687d69 100644
--- a/nixos/modules/services/networking/yggdrasil.nix
+++ b/nixos/modules/services/networking/yggdrasil.nix
@@ -108,12 +108,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = package;
-        default = pkgs.yggdrasil;
-        defaultText = literalExpression "pkgs.yggdrasil";
-        description = lib.mdDoc "Yggdrasil package to use.";
-      };
+      package = mkPackageOption pkgs "yggdrasil" { };
 
       persistentKeys = mkEnableOption (lib.mdDoc ''
         persistent keys. If enabled then keys will be generated once and Yggdrasil
diff --git a/nixos/modules/services/networking/zeronet.nix b/nixos/modules/services/networking/zeronet.nix
index 1f3711bd0d72..7e88a8b346d9 100644
--- a/nixos/modules/services/networking/zeronet.nix
+++ b/nixos/modules/services/networking/zeronet.nix
@@ -1,7 +1,8 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) generators literalExpression mkEnableOption mkIf mkOption recursiveUpdate types;
+  inherit (lib) generators literalExpression mkEnableOption mkPackageOption
+                mkIf mkOption recursiveUpdate types;
   cfg = config.services.zeronet;
   dataDir = "/var/lib/zeronet";
   configFile = pkgs.writeText "zeronet.conf" (generators.toINI {} (recursiveUpdate defaultSettings cfg.settings));
@@ -19,12 +20,7 @@ in with lib; {
   options.services.zeronet = {
     enable = mkEnableOption (lib.mdDoc "zeronet");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.zeronet;
-      defaultText = literalExpression "pkgs.zeronet";
-      description = lib.mdDoc "ZeroNet package to use";
-    };
+    package = mkPackageOption pkgs "zeronet" { };
 
     settings = mkOption {
       type = with types; attrsOf (oneOf [ str int bool (listOf str) ]);
diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix
index f78fd8642ba0..994e01d4980e 100644
--- a/nixos/modules/services/networking/zerotierone.nix
+++ b/nixos/modules/services/networking/zerotierone.nix
@@ -27,14 +27,7 @@ in
     '';
   };
 
-  options.services.zerotierone.package = mkOption {
-    default = pkgs.zerotierone;
-    defaultText = literalExpression "pkgs.zerotierone";
-    type = types.package;
-    description = lib.mdDoc ''
-      ZeroTier One package to use.
-    '';
-  };
+  options.services.zerotierone.package = mkPackageOption pkgs "zerotierone" { };
 
   config = mkIf cfg.enable {
     systemd.services.zerotierone = {
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index fa1627566ebe..6eebeb8b0a9a 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -50,12 +50,7 @@ in
       type = types.bool;
     };
 
-    package = mkOption {
-      description = lib.mdDoc "Elasticsearch package to use.";
-      default = pkgs.elasticsearch;
-      defaultText = literalExpression "pkgs.elasticsearch";
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "elasticsearch" { };
 
     listenAddress = mkOption {
       description = lib.mdDoc "Elasticsearch listen address.";
diff --git a/nixos/modules/services/search/hound.nix b/nixos/modules/services/search/hound.nix
index b41a2e2bae1f..539a322b431f 100644
--- a/nixos/modules/services/search/hound.nix
+++ b/nixos/modules/services/search/hound.nix
@@ -48,14 +48,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        default = pkgs.hound;
-        defaultText = literalExpression "pkgs.hound";
-        type = types.package;
-        description = lib.mdDoc ''
-          Package for running hound.
-        '';
-      };
+      package = mkPackageOption pkgs "hound" { };
 
       config = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/search/meilisearch.nix b/nixos/modules/services/search/meilisearch.nix
index 7c9fa62ae954..4183847d1be3 100644
--- a/nixos/modules/services/search/meilisearch.nix
+++ b/nixos/modules/services/search/meilisearch.nix
@@ -16,11 +16,10 @@ in
   options.services.meilisearch = {
     enable = mkEnableOption (lib.mdDoc "MeiliSearch - a RESTful search API");
 
-    package = mkOption {
-      description = lib.mdDoc "The package to use for meilisearch. Use this if you require specific features to be enabled. The default package has no features.";
-      default = pkgs.meilisearch;
-      defaultText = lib.literalExpression "pkgs.meilisearch";
-      type = types.package;
+    package = mkPackageOption pkgs "meilisearch" {
+      extraDescription = ''
+        Use this if you require specific features to be enabled. The default package has no features.
+      '';
     };
 
     listenAddress = mkOption {
diff --git a/nixos/modules/services/security/authelia.nix b/nixos/modules/services/security/authelia.nix
index cc55260e20f8..614b3b1e22b2 100644
--- a/nixos/modules/services/security/authelia.nix
+++ b/nixos/modules/services/security/authelia.nix
@@ -24,12 +24,7 @@ let
         '';
       };
 
-      package = mkOption {
-        default = pkgs.authelia;
-        type = types.package;
-        defaultText = literalExpression "pkgs.authelia";
-        description = mdDoc "Authelia derivation to use.";
-      };
+      package = mkPackageOption pkgs "authelia" { };
 
       user = mkOption {
         default = "authelia-${name}";
diff --git a/nixos/modules/services/security/certmgr.nix b/nixos/modules/services/security/certmgr.nix
index ca4cf5084722..db80e943973d 100644
--- a/nixos/modules/services/security/certmgr.nix
+++ b/nixos/modules/services/security/certmgr.nix
@@ -37,12 +37,7 @@ in
   options.services.certmgr = {
     enable = mkEnableOption (lib.mdDoc "certmgr");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.certmgr;
-      defaultText = literalExpression "pkgs.certmgr";
-      description = lib.mdDoc "Which certmgr package to use in the service.";
-    };
+    package = mkPackageOption pkgs "certmgr" { };
 
     defaultRemote = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix
index 235f29ab8a6a..59b9ea70209d 100644
--- a/nixos/modules/services/security/fail2ban.nix
+++ b/nixos/modules/services/security/fail2ban.nix
@@ -77,12 +77,8 @@ in
         '';
       };
 
-      package = mkOption {
-        default = pkgs.fail2ban;
-        defaultText = literalExpression "pkgs.fail2ban";
-        type = types.package;
-        example = literalExpression "pkgs.fail2ban_0_11";
-        description = lib.mdDoc "The fail2ban package to use for running the fail2ban service.";
+      package = mkPackageOption pkgs "fail2ban" {
+        example = "fail2ban_0_11";
       };
 
       packageFirewall = mkOption {
@@ -128,8 +124,8 @@ in
       };
 
       banaction-allports = mkOption {
-        default = if config.networking.nftables.enable then "nftables-allport" else "iptables-allport";
-        defaultText = literalExpression ''if config.networking.nftables.enable then "nftables-allport" else "iptables-allport"'';
+        default = if config.networking.nftables.enable then "nftables-allports" else "iptables-allports";
+        defaultText = literalExpression ''if config.networking.nftables.enable then "nftables-allports" else "iptables-allports"'';
         type = types.str;
         description = lib.mdDoc ''
           Default banning action (e.g. iptables, iptables-new, iptables-multiport,
diff --git a/nixos/modules/services/security/haka.nix b/nixos/modules/services/security/haka.nix
index c93638f44d60..dda039857401 100644
--- a/nixos/modules/services/security/haka.nix
+++ b/nixos/modules/services/security/haka.nix
@@ -57,14 +57,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "Haka");
 
-      package = mkOption {
-        default = pkgs.haka;
-        defaultText = literalExpression "pkgs.haka";
-        type = types.package;
-        description = lib.mdDoc ''
-          Which Haka derivation to use.
-        '';
-      };
+      package = mkPackageOption pkgs "haka" { };
 
       configFile = mkOption {
         default = "empty.lua";
diff --git a/nixos/modules/services/security/nginx-sso.nix b/nixos/modules/services/security/nginx-sso.nix
index 971f22ed3476..dd32b8356cbb 100644
--- a/nixos/modules/services/security/nginx-sso.nix
+++ b/nixos/modules/services/security/nginx-sso.nix
@@ -10,14 +10,7 @@ in {
   options.services.nginx.sso = {
     enable = mkEnableOption (lib.mdDoc "nginx-sso service");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.nginx-sso;
-      defaultText = literalExpression "pkgs.nginx-sso";
-      description = lib.mdDoc ''
-        The nginx-sso package that should be used.
-      '';
-    };
+    package = mkPackageOption pkgs "nginx-sso" { };
 
     configuration = mkOption {
       type = types.attrsOf types.unspecified;
diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix
index 718c3d2498ea..78916c907279 100644
--- a/nixos/modules/services/security/oauth2_proxy.nix
+++ b/nixos/modules/services/security/oauth2_proxy.nix
@@ -87,14 +87,7 @@ in
   options.services.oauth2_proxy = {
     enable = mkEnableOption (lib.mdDoc "oauth2_proxy");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.oauth2-proxy;
-      defaultText = literalExpression "pkgs.oauth2-proxy";
-      description = lib.mdDoc ''
-        The package that provides oauth2-proxy.
-      '';
-    };
+    package = mkPackageOption pkgs "oauth2-proxy" { };
 
     ##############################################
     # PROVIDER configuration
diff --git a/nixos/modules/services/security/pass-secret-service.nix b/nixos/modules/services/security/pass-secret-service.nix
index c3c70d97ff59..f864f8a26595 100644
--- a/nixos/modules/services/security/pass-secret-service.nix
+++ b/nixos/modules/services/security/pass-secret-service.nix
@@ -9,12 +9,8 @@ in
   options.services.passSecretService = {
     enable = mkEnableOption (lib.mdDoc "pass secret service");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.pass-secret-service;
-      defaultText = literalExpression "pkgs.pass-secret-service";
-      description = lib.mdDoc "Which pass-secret-service package to use.";
-      example = literalExpression "pkgs.pass-secret-service.override { python3 = pkgs.python310 }";
+    package = mkPackageOption pkgs "pass-secret-service" {
+      example = "pass-secret-service.override { python3 = pkgs.python310 }";
     };
   };
 
diff --git a/nixos/modules/services/security/sks.nix b/nixos/modules/services/security/sks.nix
index 550b61916a22..7ac5ecec0d82 100644
--- a/nixos/modules/services/security/sks.nix
+++ b/nixos/modules/services/security/sks.nix
@@ -21,12 +21,7 @@ in {
         server. You need to create "''${dataDir}/dump/*.gpg" for the initial
         import'');
 
-      package = mkOption {
-        default = pkgs.sks;
-        defaultText = literalExpression "pkgs.sks";
-        type = types.package;
-        description = lib.mdDoc "Which SKS derivation to use.";
-      };
+      package = mkPackageOption pkgs "sks" { };
 
       dataDir = mkOption {
         type = types.path;
diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix
index 9e786eb2bf06..4ff941251c99 100644
--- a/nixos/modules/services/security/tor.nix
+++ b/nixos/modules/services/security/tor.nix
@@ -230,12 +230,7 @@ in
 
       openFirewall = mkEnableOption (lib.mdDoc "opening of the relay port(s) in the firewall");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.tor;
-        defaultText = literalExpression "pkgs.tor";
-        description = lib.mdDoc "Tor package to use.";
-      };
+      package = mkPackageOption pkgs "tor" { };
 
       enableGeoIP = mkEnableOption (lib.mdDoc ''use of GeoIP databases.
         Disabling this will disable by-country statistics for bridges and relays
diff --git a/nixos/modules/services/security/usbguard.nix b/nixos/modules/services/security/usbguard.nix
index 071e69975143..f167fbb2eca8 100644
--- a/nixos/modules/services/security/usbguard.nix
+++ b/nixos/modules/services/security/usbguard.nix
@@ -39,13 +39,9 @@ in
     services.usbguard = {
       enable = mkEnableOption (lib.mdDoc "USBGuard daemon");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.usbguard;
-        defaultText = literalExpression "pkgs.usbguard";
-        description = lib.mdDoc ''
-          The usbguard package to use. If you do not need the Qt GUI, use
-          `pkgs.usbguard-nox` to save disk space.
+      package = mkPackageOption pkgs "usbguard" {
+        extraDescription = ''
+          If you do not need the Qt GUI, use `pkgs.usbguard-nox` to save disk space.
         '';
       };
 
diff --git a/nixos/modules/services/security/vault.nix b/nixos/modules/services/security/vault.nix
index 18d981cdb0d2..31782073968f 100644
--- a/nixos/modules/services/security/vault.nix
+++ b/nixos/modules/services/security/vault.nix
@@ -45,12 +45,7 @@ in
     services.vault = {
       enable = mkEnableOption (lib.mdDoc "Vault daemon");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.vault;
-        defaultText = literalExpression "pkgs.vault";
-        description = lib.mdDoc "This option specifies the vault package to use.";
-      };
+      package = mkPackageOption pkgs "vault" { };
 
       dev = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix
index 0517615a4c6a..14bbfa95a9ca 100644
--- a/nixos/modules/services/security/vaultwarden/default.nix
+++ b/nixos/modules/services/security/vaultwarden/default.nix
@@ -156,12 +156,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = package;
-      default = pkgs.vaultwarden;
-      defaultText = literalExpression "pkgs.vaultwarden";
-      description = lib.mdDoc "Vaultwarden package to use.";
-    };
+    package = mkPackageOption pkgs "vaultwarden" { };
 
     webVaultPackage = mkOption {
       type = package;
diff --git a/nixos/modules/services/security/yubikey-agent.nix b/nixos/modules/services/security/yubikey-agent.nix
index ee57ec8bf812..a9f15e4405f2 100644
--- a/nixos/modules/services/security/yubikey-agent.nix
+++ b/nixos/modules/services/security/yubikey-agent.nix
@@ -30,14 +30,7 @@ in
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.yubikey-agent;
-        defaultText = literalExpression "pkgs.yubikey-agent";
-        description = lib.mdDoc ''
-          The package used for the yubikey-agent daemon.
-        '';
-      };
+      package = mkPackageOption pkgs "yubikey-agent" { };
     };
   };
 
diff --git a/nixos/modules/services/system/automatic-timezoned.nix b/nixos/modules/services/system/automatic-timezoned.nix
index 9bdd64dd33a3..8934ed3a7ef2 100644
--- a/nixos/modules/services/system/automatic-timezoned.nix
+++ b/nixos/modules/services/system/automatic-timezoned.nix
@@ -18,14 +18,7 @@ in
           the timezone.
         '';
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.automatic-timezoned;
-        defaultText = literalExpression "pkgs.automatic-timezoned";
-        description = mdDoc ''
-          Which `automatic-timezoned` package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "automatic-timezoned" { };
     };
   };
 
diff --git a/nixos/modules/services/system/cachix-agent/default.nix b/nixos/modules/services/system/cachix-agent/default.nix
index 06494ddb631a..196d3291d555 100644
--- a/nixos/modules/services/system/cachix-agent/default.nix
+++ b/nixos/modules/services/system/cachix-agent/default.nix
@@ -35,12 +35,7 @@ in {
       description = lib.mdDoc "Cachix uri to use.";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.cachix;
-      defaultText = literalExpression "pkgs.cachix";
-      description = lib.mdDoc "Cachix Client package to use.";
-    };
+    package = mkPackageOption pkgs "cachix" { };
 
     credentialsFile = mkOption {
       type = types.path;
diff --git a/nixos/modules/services/system/cachix-watch-store.nix b/nixos/modules/services/system/cachix-watch-store.nix
index 89157b460b9a..992a59cbc075 100644
--- a/nixos/modules/services/system/cachix-watch-store.nix
+++ b/nixos/modules/services/system/cachix-watch-store.nix
@@ -47,13 +47,7 @@ in
       default = false;
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.cachix;
-      defaultText = literalExpression "pkgs.cachix";
-      description = lib.mdDoc "Cachix Client package to use.";
-    };
-
+    package = mkPackageOption pkgs "cachix" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/system/saslauthd.nix b/nixos/modules/services/system/saslauthd.nix
index 09720146aaa9..9424b6c51fc1 100644
--- a/nixos/modules/services/system/saslauthd.nix
+++ b/nixos/modules/services/system/saslauthd.nix
@@ -18,12 +18,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "saslauthd, the Cyrus SASL authentication daemon");
 
-      package = mkOption {
-        default = pkgs.cyrus_sasl.bin;
-        defaultText = literalExpression "pkgs.cyrus_sasl.bin";
-        type = types.package;
-        description = lib.mdDoc "Cyrus SASL package to use.";
-      };
+      package = mkPackageOption pkgs [ "cyrus_sasl" "bin" ] { };
 
       mechanism = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/torrent/deluge.nix b/nixos/modules/services/torrent/deluge.nix
index 003f7b2613b7..4802e3e1c63a 100644
--- a/nixos/modules/services/torrent/deluge.nix
+++ b/nixos/modules/services/torrent/deluge.nix
@@ -147,13 +147,7 @@ in {
           '';
         };
 
-        package = mkOption {
-          type = types.package;
-          example = literalExpression "pkgs.deluge-2_x";
-          description = lib.mdDoc ''
-            Deluge package to use.
-          '';
-        };
+        package = mkPackageOption pkgs "deluge-2_x" { };
       };
 
       deluge.web = {
diff --git a/nixos/modules/services/torrent/opentracker.nix b/nixos/modules/services/torrent/opentracker.nix
index 7d67491c1191..71852f24e55b 100644
--- a/nixos/modules/services/torrent/opentracker.nix
+++ b/nixos/modules/services/torrent/opentracker.nix
@@ -7,14 +7,7 @@ in {
   options.services.opentracker = {
     enable = mkEnableOption (lib.mdDoc "opentracker");
 
-    package = mkOption {
-      type = types.package;
-      description = lib.mdDoc ''
-        opentracker package to use
-      '';
-      default = pkgs.opentracker;
-      defaultText = literalExpression "pkgs.opentracker";
-    };
+    package = mkPackageOption pkgs "opentracker" { };
 
     extraOptions = mkOption {
       type = types.separatedString " ";
diff --git a/nixos/modules/services/torrent/rtorrent.nix b/nixos/modules/services/torrent/rtorrent.nix
index 64cda7fb675f..699f3be82a9d 100644
--- a/nixos/modules/services/torrent/rtorrent.nix
+++ b/nixos/modules/services/torrent/rtorrent.nix
@@ -53,14 +53,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.rtorrent;
-      defaultText = literalExpression "pkgs.rtorrent";
-      description = lib.mdDoc ''
-        The rtorrent package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "rtorrent" { };
 
     port = mkOption {
       type = types.port;
diff --git a/nixos/modules/services/video/epgstation/default.nix b/nixos/modules/services/video/epgstation/default.nix
index fca483b0dbd7..a7468e7cc2b6 100644
--- a/nixos/modules/services/video/epgstation/default.nix
+++ b/nixos/modules/services/video/epgstation/default.nix
@@ -80,11 +80,11 @@ in
   options.services.epgstation = {
     enable = lib.mkEnableOption (lib.mdDoc description);
 
-    package = lib.mkPackageOptionMD pkgs "epgstation" { };
+    package = lib.mkPackageOption pkgs "epgstation" { };
 
-    ffmpeg = lib.mkPackageOptionMD pkgs "ffmpeg" {
-      default = [ "ffmpeg-headless" ];
-      example = "pkgs.ffmpeg-full";
+    ffmpeg = lib.mkPackageOption pkgs "ffmpeg" {
+      default = "ffmpeg-headless";
+      example = "ffmpeg-full";
     };
 
     usePreconfiguredStreaming = lib.mkOption {
diff --git a/nixos/modules/services/video/frigate.nix b/nixos/modules/services/video/frigate.nix
index 8db2bfae80ac..146e968780c3 100644
--- a/nixos/modules/services/video/frigate.nix
+++ b/nixos/modules/services/video/frigate.nix
@@ -10,6 +10,7 @@ let
     mkDefault
     mdDoc
     mkEnableOption
+    mkPackageOption
     mkIf
     mkOption
     types;
@@ -62,13 +63,7 @@ in
   options.services.frigate = with types; {
     enable = mkEnableOption (mdDoc "Frigate NVR");
 
-    package = mkOption {
-      type = package;
-      default = pkgs.frigate;
-      description = mdDoc ''
-        The frigate package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "frigate" { };
 
     hostname = mkOption {
       type = str;
diff --git a/nixos/modules/services/video/unifi-video.nix b/nixos/modules/services/video/unifi-video.nix
index 5c93f60cbd79..518977e49bae 100644
--- a/nixos/modules/services/video/unifi-video.nix
+++ b/nixos/modules/services/video/unifi-video.nix
@@ -103,31 +103,12 @@ in
       '';
     };
 
-    jrePackage = mkOption {
-      type = types.package;
-      default = pkgs.jre8;
-      defaultText = literalExpression "pkgs.jre8";
-      description = lib.mdDoc ''
-        The JRE package to use. Check the release notes to ensure it is supported.
-      '';
-    };
+    jrePackage = mkPackageOption pkgs "jre8" { };
 
-    unifiVideoPackage = mkOption {
-      type = types.package;
-      default = pkgs.unifi-video;
-      defaultText = literalExpression "pkgs.unifi-video";
-      description = lib.mdDoc ''
-        The unifi-video package to use.
-      '';
-    };
+    unifiVideoPackage = mkPackageOption pkgs "unifi-video" { };
 
-    mongodbPackage = mkOption {
-      type = types.package;
-      default = pkgs.mongodb-4_4;
-      defaultText = literalExpression "pkgs.mongodb";
-      description = lib.mdDoc ''
-        The mongodb package to use.
-      '';
+    mongodbPackage = mkPackageOption pkgs "mongodb" {
+      default = "mongodb-4_4";
     };
 
     logDir = mkOption {
diff --git a/nixos/modules/services/web-apps/akkoma.nix b/nixos/modules/services/web-apps/akkoma.nix
index 8a8ed49115fd..8980556ab014 100644
--- a/nixos/modules/services/web-apps/akkoma.nix
+++ b/nixos/modules/services/web-apps/akkoma.nix
@@ -352,12 +352,7 @@ in {
     services.akkoma = {
       enable = mkEnableOption (mdDoc "Akkoma");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.akkoma;
-        defaultText = literalExpression "pkgs.akkoma";
-        description = mdDoc "Akkoma package to use.";
-      };
+      package = mkPackageOption pkgs "akkoma" { };
 
       user = mkOption {
         type = types.nonEmptyStr;
diff --git a/nixos/modules/services/web-apps/atlassian/confluence.nix b/nixos/modules/services/web-apps/atlassian/confluence.nix
index fe98c1777ea0..aa13659fcc30 100644
--- a/nixos/modules/services/web-apps/atlassian/confluence.nix
+++ b/nixos/modules/services/web-apps/atlassian/confluence.nix
@@ -133,18 +133,14 @@ in
         };
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.atlassian-confluence;
-        defaultText = literalExpression "pkgs.atlassian-confluence";
-        description = lib.mdDoc "Atlassian Confluence package to use.";
-      };
-
-      jrePackage = mkOption {
-        type = types.package;
-        default = pkgs.oraclejre8;
-        defaultText = literalExpression "pkgs.oraclejre8";
-        description = lib.mdDoc "Note that Atlassian only support the Oracle JRE (JRASERVER-46152).";
+      package = mkPackageOption pkgs "atlassian-confluence" { };
+
+      jrePackage = mkPackageOption pkgs "oraclejre8" {
+        extraDescription = ''
+        ::: {.note }
+        Atlassian only supports the Oracle JRE (JRASERVER-46152).
+        :::
+        '';
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/atlassian/crowd.nix b/nixos/modules/services/web-apps/atlassian/crowd.nix
index c8d1eaef31d8..eed1a127fe4f 100644
--- a/nixos/modules/services/web-apps/atlassian/crowd.nix
+++ b/nixos/modules/services/web-apps/atlassian/crowd.nix
@@ -115,18 +115,14 @@ in
         };
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.atlassian-crowd;
-        defaultText = literalExpression "pkgs.atlassian-crowd";
-        description = lib.mdDoc "Atlassian Crowd package to use.";
-      };
-
-      jrePackage = mkOption {
-        type = types.package;
-        default = pkgs.oraclejre8;
-        defaultText = literalExpression "pkgs.oraclejre8";
-        description = lib.mdDoc "Note that Atlassian only support the Oracle JRE (JRASERVER-46152).";
+      package = mkPackageOption pkgs "atlassian-crowd" { };
+
+      jrePackage = mkPackageOption pkgs "oraclejre8" {
+        extraDescription = ''
+        ::: {.note }
+        Atlassian only supports the Oracle JRE (JRASERVER-46152).
+        :::
+        '';
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/atlassian/jira.nix b/nixos/modules/services/web-apps/atlassian/jira.nix
index 4cc858216944..a9f337810a0f 100644
--- a/nixos/modules/services/web-apps/atlassian/jira.nix
+++ b/nixos/modules/services/web-apps/atlassian/jira.nix
@@ -132,18 +132,14 @@ in
         };
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.atlassian-jira;
-        defaultText = literalExpression "pkgs.atlassian-jira";
-        description = lib.mdDoc "Atlassian JIRA package to use.";
-      };
-
-      jrePackage = mkOption {
-        type = types.package;
-        default = pkgs.oraclejre8;
-        defaultText = literalExpression "pkgs.oraclejre8";
-        description = lib.mdDoc "Note that Atlassian only support the Oracle JRE (JRASERVER-46152).";
+      package = mkPackageOption pkgs "atlassian-jira" { };
+
+      jrePackage = mkPackageOption pkgs "oraclejre8" {
+        extraDescription = ''
+        ::: {.note }
+        Atlassian only supports the Oracle JRE (JRASERVER-46152).
+        :::
+        '';
       };
     };
   };
diff --git a/nixos/modules/services/web-apps/coder.nix b/nixos/modules/services/web-apps/coder.nix
index f65211308c40..0f5cb2c3c689 100644
--- a/nixos/modules/services/web-apps/coder.nix
+++ b/nixos/modules/services/web-apps/coder.nix
@@ -36,14 +36,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.coder;
-        description = lib.mdDoc ''
-          Package to use for the service.
-        '';
-        defaultText = literalExpression "pkgs.coder";
-      };
+      package = mkPackageOption pkgs "coder" { };
 
       homeDir = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/web-apps/documize.nix b/nixos/modules/services/web-apps/documize.nix
index f70da0829f44..6f88b3f3c6d2 100644
--- a/nixos/modules/services/web-apps/documize.nix
+++ b/nixos/modules/services/web-apps/documize.nix
@@ -23,14 +23,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.documize-community;
-      defaultText = literalExpression "pkgs.documize-community";
-      description = lib.mdDoc ''
-        Which package to use for documize.
-      '';
-    };
+    package = mkPackageOption pkgs "documize-community" { };
 
     salt = mkOption {
       type = types.nullOr types.str;
diff --git a/nixos/modules/services/web-apps/dokuwiki.nix b/nixos/modules/services/web-apps/dokuwiki.nix
index 9e9bfb1bfd83..1df1cbf9f0e1 100644
--- a/nixos/modules/services/web-apps/dokuwiki.nix
+++ b/nixos/modules/services/web-apps/dokuwiki.nix
@@ -182,12 +182,7 @@ let
       options = {
         enable = mkEnableOption (lib.mdDoc "DokuWiki web application");
 
-        package = mkOption {
-          type = types.package;
-          default = pkgs.dokuwiki;
-          defaultText = literalExpression "pkgs.dokuwiki";
-          description = lib.mdDoc "Which DokuWiki package to use.";
-        };
+        package = mkPackageOption pkgs "dokuwiki" { };
 
         stateDir = mkOption {
           type = types.path;
@@ -335,14 +330,9 @@ let
           '';
         };
 
-        phpPackage = mkOption {
-          type = types.package;
-          relatedPackages = [ "php81" "php82" ];
-          default = pkgs.php81;
-          defaultText = "pkgs.php81";
-          description = lib.mdDoc ''
-            PHP package to use for this dokuwiki site.
-          '';
+        phpPackage = mkPackageOption pkgs "php" {
+          default = "php81";
+          example = "php82";
         };
 
         phpOptions = mkOption {
diff --git a/nixos/modules/services/web-apps/engelsystem.nix b/nixos/modules/services/web-apps/engelsystem.nix
index 138e2f3f1b90..669620debce5 100644
--- a/nixos/modules/services/web-apps/engelsystem.nix
+++ b/nixos/modules/services/web-apps/engelsystem.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, utils, ... }:
 
 let
-  inherit (lib) mkDefault mkEnableOption mkIf mkOption types literalExpression;
+  inherit (lib) mkDefault mkEnableOption mkIf mkOption types mkPackageOption;
   cfg = config.services.engelsystem;
 in {
   options = {
@@ -22,12 +22,7 @@ in {
         description = lib.mdDoc "Domain to serve on.";
       };
 
-      package = mkOption {
-        type = types.package;
-        description = lib.mdDoc "Engelsystem package used for the service.";
-        default = pkgs.engelsystem;
-        defaultText = literalExpression "pkgs.engelsystem";
-      };
+      package = mkPackageOption pkgs "engelsystem" { };
 
       createDatabase = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/web-apps/ethercalc.nix b/nixos/modules/services/web-apps/ethercalc.nix
index a5be86a34aa6..a38e89ec0de9 100644
--- a/nixos/modules/services/web-apps/ethercalc.nix
+++ b/nixos/modules/services/web-apps/ethercalc.nix
@@ -24,12 +24,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        default = pkgs.ethercalc;
-        defaultText = literalExpression "pkgs.ethercalc";
-        type = types.package;
-        description = lib.mdDoc "Ethercalc package to use.";
-      };
+      package = mkPackageOption pkgs "ethercalc" { };
 
       host = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/web-apps/fluidd.nix b/nixos/modules/services/web-apps/fluidd.nix
index d4b86b9dfb39..1d9b56f5ccf2 100644
--- a/nixos/modules/services/web-apps/fluidd.nix
+++ b/nixos/modules/services/web-apps/fluidd.nix
@@ -8,12 +8,7 @@ in
   options.services.fluidd = {
     enable = mkEnableOption (lib.mdDoc "Fluidd, a Klipper web interface for managing your 3d printer");
 
-    package = mkOption {
-      type = types.package;
-      description = lib.mdDoc "Fluidd package to be used in the module";
-      default = pkgs.fluidd;
-      defaultText = literalExpression "pkgs.fluidd";
-    };
+    package = mkPackageOption pkgs "fluidd" { };
 
     hostName = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/web-apps/freshrss.nix b/nixos/modules/services/web-apps/freshrss.nix
index 8b4ea2aa53c9..9683730bbe1f 100644
--- a/nixos/modules/services/web-apps/freshrss.nix
+++ b/nixos/modules/services/web-apps/freshrss.nix
@@ -12,12 +12,7 @@ in
   options.services.freshrss = {
     enable = mkEnableOption (mdDoc "FreshRSS feed reader");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.freshrss;
-      defaultText = lib.literalExpression "pkgs.freshrss";
-      description = mdDoc "Which FreshRSS package to use.";
-    };
+    package = mkPackageOption pkgs "freshrss" { };
 
     defaultUser = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/web-apps/galene.nix b/nixos/modules/services/web-apps/galene.nix
index 81fed8a0b99a..28d4069ec385 100644
--- a/nixos/modules/services/web-apps/galene.nix
+++ b/nixos/modules/services/web-apps/galene.nix
@@ -110,14 +110,7 @@ in
         description = lib.mdDoc "Web server directory.";
       };
 
-      package = mkOption {
-        default = pkgs.galene;
-        defaultText = literalExpression "pkgs.galene";
-        type = types.package;
-        description = lib.mdDoc ''
-          Package for running Galene.
-        '';
-      };
+      package = mkPackageOption pkgs "galene" { };
     };
   };
 
diff --git a/nixos/modules/services/web-apps/gerrit.nix b/nixos/modules/services/web-apps/gerrit.nix
index ab2eeea09bdc..5c62a7ebbd93 100644
--- a/nixos/modules/services/web-apps/gerrit.nix
+++ b/nixos/modules/services/web-apps/gerrit.nix
@@ -61,19 +61,9 @@ in
     services.gerrit = {
       enable = mkEnableOption (lib.mdDoc "Gerrit service");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.gerrit;
-        defaultText = literalExpression "pkgs.gerrit";
-        description = lib.mdDoc "Gerrit package to use";
-      };
+      package = mkPackageOption pkgs "gerrit" { };
 
-      jvmPackage = mkOption {
-        type = types.package;
-        default = pkgs.jre_headless;
-        defaultText = literalExpression "pkgs.jre_headless";
-        description = lib.mdDoc "Java Runtime Environment package to use";
-      };
+      jvmPackage = mkPackageOption pkgs "jre_headless" { };
 
       jvmOpts = mkOption {
         type = types.listOf types.str;
diff --git a/nixos/modules/services/web-apps/healthchecks.nix b/nixos/modules/services/web-apps/healthchecks.nix
index b92525075541..e5e425a29d54 100644
--- a/nixos/modules/services/web-apps/healthchecks.nix
+++ b/nixos/modules/services/web-apps/healthchecks.nix
@@ -33,12 +33,7 @@ in
       '';
     };
 
-    package = mkOption {
-      default = pkgs.healthchecks;
-      defaultText = literalExpression "pkgs.healthchecks";
-      type = types.package;
-      description = lib.mdDoc "healthchecks package to use.";
-    };
+    package = mkPackageOption pkgs "healthchecks" { };
 
     user = mkOption {
       default = defaultUser;
diff --git a/nixos/modules/services/web-apps/invidious.nix b/nixos/modules/services/web-apps/invidious.nix
index e4fbc6fd9368..cfba3c8a2970 100644
--- a/nixos/modules/services/web-apps/invidious.nix
+++ b/nixos/modules/services/web-apps/invidious.nix
@@ -185,12 +185,7 @@ in
   options.services.invidious = {
     enable = lib.mkEnableOption (lib.mdDoc "Invidious");
 
-    package = lib.mkOption {
-      type = types.package;
-      default = pkgs.invidious;
-      defaultText = lib.literalExpression "pkgs.invidious";
-      description = lib.mdDoc "The Invidious package to use.";
-    };
+    package = lib.mkPackageOption pkgs "invidious" { };
 
     settings = lib.mkOption {
       type = settingsFormat.type;
diff --git a/nixos/modules/services/web-apps/jirafeau.nix b/nixos/modules/services/web-apps/jirafeau.nix
index b2e274167164..5f754d824a28 100644
--- a/nixos/modules/services/web-apps/jirafeau.nix
+++ b/nixos/modules/services/web-apps/jirafeau.nix
@@ -92,12 +92,7 @@ in
       description = lib.mdDoc "Extra configuration for the nginx virtual host of Jirafeau.";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.jirafeau;
-      defaultText = literalExpression "pkgs.jirafeau";
-      description = lib.mdDoc "Jirafeau package to use";
-    };
+    package = mkPackageOption pkgs "jirafeau" { };
 
     poolConfig = mkOption {
       type = with types; attrsOf (oneOf [ str int bool ]);
diff --git a/nixos/modules/services/web-apps/jitsi-meet.nix b/nixos/modules/services/web-apps/jitsi-meet.nix
index c0f9d785eea2..0c0eb66e65b7 100644
--- a/nixos/modules/services/web-apps/jitsi-meet.nix
+++ b/nixos/modules/services/web-apps/jitsi-meet.nix
@@ -479,7 +479,7 @@ in
         extraConfig =
         let
           templatedJitsiMeet = pkgs.runCommand "templated-jitsi-meet" { } ''
-            cp -R ${pkgs.jitsi-meet}/* .
+            cp -R --no-preserve=all ${pkgs.jitsi-meet}/* .
             for file in *.html **/*.html ; do
               ${pkgs.sd}/bin/sd '<!--#include virtual="(.*)" -->' '{{ include "$1" }}' $file
             done
diff --git a/nixos/modules/services/web-apps/keycloak.nix b/nixos/modules/services/web-apps/keycloak.nix
index a7e4fab8ea28..5d44bdee64a7 100644
--- a/nixos/modules/services/web-apps/keycloak.nix
+++ b/nixos/modules/services/web-apps/keycloak.nix
@@ -11,6 +11,7 @@ let
     mkChangedOptionModule
     mkRenamedOptionModule
     mkRemovedOptionModule
+    mkPackageOption
     concatStringsSep
     mapAttrsToList
     escapeShellArg
@@ -246,14 +247,7 @@ in
         };
       };
 
-      package = mkOption {
-        type = package;
-        default = pkgs.keycloak;
-        defaultText = literalExpression "pkgs.keycloak";
-        description = lib.mdDoc ''
-          Keycloak package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "keycloak" { };
 
       initialAdminPassword = mkOption {
         type = str;
diff --git a/nixos/modules/services/web-apps/lanraragi.nix b/nixos/modules/services/web-apps/lanraragi.nix
index f1ab8b8b4eb4..6e452e7a3b35 100644
--- a/nixos/modules/services/web-apps/lanraragi.nix
+++ b/nixos/modules/services/web-apps/lanraragi.nix
@@ -72,11 +72,10 @@ in
         "HOME" = "/var/lib/lanraragi";
       };
       preStart = ''
-        REDIS_PASS=${lib.optionalString (cfg.redis.passwordFile != null) "$(head -n1 ${cfg.redis.passwordFile})"}
         cat > lrr.conf <<EOF
         {
           redis_address => "127.0.0.1:${toString cfg.redis.port}",
-          redis_password => "$REDIS_PASS",
+          redis_password => "${lib.optionalString (cfg.redis.passwordFile != null) ''$(head -n1 ${cfg.redis.passwordFile})''}",
           redis_database => "0",
           redis_database_minion => "1",
           redis_database_config => "2",
@@ -84,15 +83,9 @@ in
         }
         EOF
       '' + lib.optionalString (cfg.passwordFile != null) ''
-        PASS_HASH=$(
-          PASS=$(head -n1 ${cfg.passwordFile}) ${cfg.package.perlEnv}/bin/perl -I${cfg.package}/share/lanraragi/lib -e \
-            'use LANraragi::Controller::Config; print LANraragi::Controller::Config::make_password_hash($ENV{PASS})' \
-            2>/dev/null
-        )
-
-        ${lib.getExe pkgs.redis} -h 127.0.0.1 -p ${toString cfg.redis.port} -a "$REDIS_PASS" <<EOF
+        ${lib.getExe pkgs.redis} -h 127.0.0.1 -p ${toString cfg.redis.port} ${lib.optionalString (cfg.redis.passwordFile != null) ''-a "$(head -n1 ${cfg.redis.passwordFile})"''}<<EOF
           SELECT 2
-          HSET LRR_CONFIG password $PASS_HASH
+          HSET LRR_CONFIG password $(${cfg.package}/bin/helpers/lrr-make-password-hash $(head -n1 ${cfg.passwordFile}))
         EOF
       '';
     };
diff --git a/nixos/modules/services/web-apps/mainsail.nix b/nixos/modules/services/web-apps/mainsail.nix
index f335d9b015d4..95de2c5640b4 100644
--- a/nixos/modules/services/web-apps/mainsail.nix
+++ b/nixos/modules/services/web-apps/mainsail.nix
@@ -8,12 +8,7 @@ in
   options.services.mainsail = {
     enable = mkEnableOption (lib.mdDoc "a modern and responsive user interface for Klipper");
 
-    package = mkOption {
-      type = types.package;
-      description = lib.mdDoc "Mainsail package to be used in the module";
-      default = pkgs.mainsail;
-      defaultText = literalExpression "pkgs.mainsail";
-    };
+    package = mkPackageOption pkgs "mainsail" { };
 
     hostName = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/web-apps/matomo.nix b/nixos/modules/services/web-apps/matomo.nix
index eadf8b62b977..fef5dc82de04 100644
--- a/nixos/modules/services/web-apps/matomo.nix
+++ b/nixos/modules/services/web-apps/matomo.nix
@@ -36,16 +36,7 @@ in {
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        description = lib.mdDoc ''
-          Matomo package for the service to use.
-          This can be used to point to newer releases from nixos-unstable,
-          as they don't get backported if they are not security-relevant.
-        '';
-        default = pkgs.matomo;
-        defaultText = literalExpression "pkgs.matomo";
-      };
+      package = mkPackageOption pkgs "matomo" { };
 
       webServerUser = mkOption {
         type = types.nullOr types.str;
diff --git a/nixos/modules/services/web-apps/mattermost.nix b/nixos/modules/services/web-apps/mattermost.nix
index 24f3b3331845..f19465eeb59a 100644
--- a/nixos/modules/services/web-apps/mattermost.nix
+++ b/nixos/modules/services/web-apps/mattermost.nix
@@ -102,12 +102,7 @@ in
     services.mattermost = {
       enable = mkEnableOption (lib.mdDoc "Mattermost chat server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.mattermost;
-        defaultText = lib.literalExpression "pkgs.mattermost";
-        description = lib.mdDoc "Mattermost derivation to use.";
-      };
+      package = mkPackageOption pkgs "mattermostl" { };
 
       statePath = mkOption {
         type = types.str;
@@ -250,12 +245,7 @@ in
 
       matterircd = {
         enable = mkEnableOption (lib.mdDoc "Mattermost IRC bridge");
-        package = mkOption {
-          type = types.package;
-          default = pkgs.matterircd;
-          defaultText = lib.literalExpression "pkgs.matterircd";
-          description = lib.mdDoc "matterircd derivation to use.";
-        };
+        package = mkPackageOption pkgs "matterircd" { };
         parameters = mkOption {
           type = types.listOf types.str;
           default = [ ];
diff --git a/nixos/modules/services/web-apps/mediawiki.nix b/nixos/modules/services/web-apps/mediawiki.nix
index 0cfa4514542b..5549b6ae1eaa 100644
--- a/nixos/modules/services/web-apps/mediawiki.nix
+++ b/nixos/modules/services/web-apps/mediawiki.nix
@@ -2,7 +2,7 @@
 
 let
 
-  inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption;
+  inherit (lib) mkDefault mkEnableOption mkPackageOption mkForce mkIf mkMerge mkOption;
   inherit (lib) concatStringsSep literalExpression mapAttrsToList optional optionals optionalString types;
 
   cfg = config.services.mediawiki;
@@ -194,12 +194,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "MediaWiki");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.mediawiki;
-        defaultText = literalExpression "pkgs.mediawiki";
-        description = lib.mdDoc "Which MediaWiki package to use.";
-      };
+      package = mkPackageOption pkgs "mediawiki" { };
 
       finalPackage = mkOption {
         type = types.package;
diff --git a/nixos/modules/services/web-apps/meme-bingo-web.nix b/nixos/modules/services/web-apps/meme-bingo-web.nix
index 652dc8840252..fe68bbecca57 100644
--- a/nixos/modules/services/web-apps/meme-bingo-web.nix
+++ b/nixos/modules/services/web-apps/meme-bingo-web.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) mkEnableOption mkIf mkOption mdDoc types literalExpression;
+  inherit (lib) mkEnableOption mkPackageOption mkIf mkOption mdDoc types literalExpression;
 
   cfg = config.services.meme-bingo-web;
 in {
@@ -13,12 +13,7 @@ in {
         Note: The application's author suppose to run meme-bingo-web behind a reverse proxy for SSL and HTTP/3
       '');
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.meme-bingo-web;
-        defaultText = literalExpression "pkgs.meme-bingo-web";
-        description = mdDoc "meme-bingo-web package to use.";
-      };
+      package = mkPackageOption pkgs "meme-bingo-web" { };
 
       baseUrl = mkOption {
         description = mdDoc ''
diff --git a/nixos/modules/services/web-apps/miniflux.nix b/nixos/modules/services/web-apps/miniflux.nix
index 5c8c93c13c43..a500008fc792 100644
--- a/nixos/modules/services/web-apps/miniflux.nix
+++ b/nixos/modules/services/web-apps/miniflux.nix
@@ -18,12 +18,7 @@ in
     services.miniflux = {
       enable = mkEnableOption (lib.mdDoc "miniflux and creates a local postgres database for it");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.miniflux;
-        defaultText = literalExpression "pkgs.miniflux";
-        description = lib.mdDoc "Miniflux package to use.";
-      };
+      package = mkPackageOption pkgs "miniflux" { };
 
       config = mkOption {
         type = types.attrsOf types.str;
diff --git a/nixos/modules/services/web-apps/moodle.nix b/nixos/modules/services/web-apps/moodle.nix
index 04ae6bd7f175..ce6a80054725 100644
--- a/nixos/modules/services/web-apps/moodle.nix
+++ b/nixos/modules/services/web-apps/moodle.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types;
+  inherit (lib) mkDefault mkEnableOption mkPackageOption mkForce mkIf mkMerge mkOption types;
   inherit (lib) concatStringsSep literalExpression mapAttrsToList optional optionalString;
 
   cfg = config.services.moodle;
@@ -66,12 +66,7 @@ in
   options.services.moodle = {
     enable = mkEnableOption (lib.mdDoc "Moodle web application");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.moodle;
-      defaultText = literalExpression "pkgs.moodle";
-      description = lib.mdDoc "The Moodle package to use.";
-    };
+    package = mkPackageOption pkgs "moodle" { };
 
     initialPassword = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index d3d318304ee9..6c50ea3c81ef 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -190,13 +190,8 @@ in {
       description = lib.mdDoc "Which package to use for the Nextcloud instance.";
       relatedPackages = [ "nextcloud26" "nextcloud27" ];
     };
-    phpPackage = mkOption {
-      type = types.package;
-      relatedPackages = [ "php81" "php82" ];
-      defaultText = "pkgs.php";
-      description = lib.mdDoc ''
-        PHP package to use for Nextcloud.
-      '';
+    phpPackage = mkPackageOption pkgs "php" {
+      example = "php82";
     };
 
     maxUploadSize = mkOption {
diff --git a/nixos/modules/services/web-apps/node-red.nix b/nixos/modules/services/web-apps/node-red.nix
index f4d4ad9681a6..d775042fed16 100644
--- a/nixos/modules/services/web-apps/node-red.nix
+++ b/nixos/modules/services/web-apps/node-red.nix
@@ -19,12 +19,7 @@ in
   options.services.node-red = {
     enable = mkEnableOption (lib.mdDoc "the Node-RED service");
 
-    package = mkOption {
-      default = pkgs.nodePackages.node-red;
-      defaultText = literalExpression "pkgs.nodePackages.node-red";
-      type = types.package;
-      description = lib.mdDoc "Node-RED package to use.";
-    };
+    package = mkPackageOption pkgs "node-red" { };
 
     openFirewall = mkOption {
       type = types.bool;
diff --git a/nixos/modules/services/web-apps/onlyoffice.nix b/nixos/modules/services/web-apps/onlyoffice.nix
index f958566b91f0..343ca80c9fc2 100644
--- a/nixos/modules/services/web-apps/onlyoffice.nix
+++ b/nixos/modules/services/web-apps/onlyoffice.nix
@@ -26,12 +26,7 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.onlyoffice-documentserver;
-      defaultText = lib.literalExpression "pkgs.onlyoffice-documentserver";
-      description = lib.mdDoc "Which package to use for the OnlyOffice instance.";
-    };
+    package = mkPackageOption pkgs "onlyoffice-documentserver" { };
 
     port = mkOption {
       type = types.port;
diff --git a/nixos/modules/services/web-apps/openwebrx.nix b/nixos/modules/services/web-apps/openwebrx.nix
index 72c5d6c7818c..ddc2d66e723c 100644
--- a/nixos/modules/services/web-apps/openwebrx.nix
+++ b/nixos/modules/services/web-apps/openwebrx.nix
@@ -6,12 +6,7 @@ in
   options.services.openwebrx = with lib; {
     enable = mkEnableOption (lib.mdDoc "OpenWebRX Web interface for Software-Defined Radios on http://localhost:8073");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.openwebrx;
-      defaultText = literalExpression "pkgs.openwebrx";
-      description = lib.mdDoc "OpenWebRX package to use for the service";
-    };
+    package = mkPackageOption pkgs "openwebrx" { };
   };
 
   config = lib.mkIf cfg.enable {
diff --git a/nixos/modules/services/web-apps/pgpkeyserver-lite.nix b/nixos/modules/services/web-apps/pgpkeyserver-lite.nix
index dd51bacd75ea..7a5ab579c408 100644
--- a/nixos/modules/services/web-apps/pgpkeyserver-lite.nix
+++ b/nixos/modules/services/web-apps/pgpkeyserver-lite.nix
@@ -20,14 +20,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "pgpkeyserver-lite on a nginx vHost proxying to a gpg keyserver");
 
-      package = mkOption {
-        default = pkgs.pgpkeyserver-lite;
-        defaultText = literalExpression "pkgs.pgpkeyserver-lite";
-        type = types.package;
-        description = lib.mdDoc ''
-          Which webgui derivation to use.
-        '';
-      };
+      package = mkPackageOption pkgs "pgpkeyserver-lite" { };
 
       hostname = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/web-apps/phylactery.nix b/nixos/modules/services/web-apps/phylactery.nix
index 723b38ee75d9..488373d0e426 100644
--- a/nixos/modules/services/web-apps/phylactery.nix
+++ b/nixos/modules/services/web-apps/phylactery.nix
@@ -22,12 +22,7 @@ in {
       description = lib.mdDoc "Path to CBZ library";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.phylactery;
-      defaultText = literalExpression "pkgs.phylactery";
-      description = lib.mdDoc "The Phylactery package to use";
-    };
+    package = mkPackageOption pkgs "phylactery" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/web-apps/pict-rs.nix b/nixos/modules/services/web-apps/pict-rs.nix
index e1b8c8333553..983342c37732 100644
--- a/nixos/modules/services/web-apps/pict-rs.nix
+++ b/nixos/modules/services/web-apps/pict-rs.nix
@@ -14,13 +14,7 @@ in
   options.services.pict-rs = {
     enable = lib.mkEnableOption (lib.mdDoc "pict-rs server");
 
-    package = mkOption {
-      type = types.package;
-      example = lib.literalExpression "pkgs.pict-rs";
-      description = lib.mdDoc ''
-        pict-rs package to use.
-      '';
-    };
+    package = lib.mkPackageOption pkgs "pict-rs" { };
 
     dataDir = mkOption {
       type = types.path;
diff --git a/nixos/modules/services/web-apps/plantuml-server.nix b/nixos/modules/services/web-apps/plantuml-server.nix
index 1fa69814c6c9..b7bdf997d955 100644
--- a/nixos/modules/services/web-apps/plantuml-server.nix
+++ b/nixos/modules/services/web-apps/plantuml-server.nix
@@ -7,7 +7,7 @@ let
     mkEnableOption
     mkIf
     mkOption
-    mkPackageOptionMD
+    mkPackageOption
     mkRemovedOptionModule
     types
     ;
@@ -25,12 +25,12 @@ in
     services.plantuml-server = {
       enable = mkEnableOption (mdDoc "PlantUML server");
 
-      package = mkPackageOptionMD pkgs "plantuml-server" { };
+      package = mkPackageOption pkgs "plantuml-server" { };
 
       packages = {
-        jdk = mkPackageOptionMD pkgs "jdk" { };
-        jetty = mkPackageOptionMD pkgs "jetty" {
-          default = "jetty_11";
+        jdk = mkPackageOption pkgs "jdk" { };
+        jetty = mkPackageOption pkgs "jetty" {
+          default = [ "jetty_11" ];
           extraDescription = ''
             At the time of writing (v1.2023.12), PlantUML Server does not support
             Jetty versions higher than 12.x.
@@ -78,7 +78,7 @@ in
         description = mdDoc "Limits image width and height.";
       };
 
-      graphvizPackage = mkPackageOptionMD pkgs "graphviz" { };
+      graphvizPackage = mkPackageOption pkgs "graphviz" { };
 
       plantumlStats = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/web-apps/sftpgo.nix b/nixos/modules/services/web-apps/sftpgo.nix
index 846478ecbd6d..1b5111e5a81c 100644
--- a/nixos/modules/services/web-apps/sftpgo.nix
+++ b/nixos/modules/services/web-apps/sftpgo.nix
@@ -23,14 +23,7 @@ in
       description = mdDoc "sftpgo";
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.sftpgo;
-      defaultText = literalExpression "pkgs.sftpgo";
-      description = mdDoc ''
-        Which SFTPGo package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "sftpgo" { };
 
     extraArgs = mkOption {
       type = with types; listOf str;
diff --git a/nixos/modules/services/web-apps/shiori.nix b/nixos/modules/services/web-apps/shiori.nix
index 71b5ad4d4c06..f9026e04d155 100644
--- a/nixos/modules/services/web-apps/shiori.nix
+++ b/nixos/modules/services/web-apps/shiori.nix
@@ -8,12 +8,7 @@ in {
     services.shiori = {
       enable = mkEnableOption (lib.mdDoc "Shiori simple bookmarks manager");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.shiori;
-        defaultText = literalExpression "pkgs.shiori";
-        description = lib.mdDoc "The Shiori package to use.";
-      };
+      package = mkPackageOption pkgs "shiori" { };
 
       address = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/web-apps/vikunja.nix b/nixos/modules/services/web-apps/vikunja.nix
index 6b1d4da532bf..b893f2c1f33c 100644
--- a/nixos/modules/services/web-apps/vikunja.nix
+++ b/nixos/modules/services/web-apps/vikunja.nix
@@ -11,18 +11,8 @@ let
 in {
   options.services.vikunja = with lib; {
     enable = mkEnableOption (lib.mdDoc "vikunja service");
-    package-api = mkOption {
-      default = pkgs.vikunja-api;
-      type = types.package;
-      defaultText = literalExpression "pkgs.vikunja-api";
-      description = lib.mdDoc "vikunja-api derivation to use.";
-    };
-    package-frontend = mkOption {
-      default = pkgs.vikunja-frontend;
-      type = types.package;
-      defaultText = literalExpression "pkgs.vikunja-frontend";
-      description = lib.mdDoc "vikunja-frontend derivation to use.";
-    };
+    package-api = mkPackageOption pkgs "vikunja-api" { };
+    package-frontend = mkPackageOption pkgs "vikunja-frontend" { };
     environmentFiles = mkOption {
       type = types.listOf types.path;
       default = [ ];
diff --git a/nixos/modules/services/web-apps/whitebophir.nix b/nixos/modules/services/web-apps/whitebophir.nix
index b673a7c1179e..dabcf38b2dbd 100644
--- a/nixos/modules/services/web-apps/whitebophir.nix
+++ b/nixos/modules/services/web-apps/whitebophir.nix
@@ -9,12 +9,7 @@ in {
     services.whitebophir = {
       enable = mkEnableOption (lib.mdDoc "whitebophir, an online collaborative whiteboard server (persistent state will be maintained under {file}`/var/lib/whitebophir`)");
 
-      package = mkOption {
-        default = pkgs.whitebophir;
-        defaultText = literalExpression "pkgs.whitebophir";
-        type = types.package;
-        description = lib.mdDoc "Whitebophir package to use.";
-      };
+      package = mkPackageOption pkgs "whitebophir" { };
 
       listenAddress = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/web-apps/wordpress.nix b/nixos/modules/services/web-apps/wordpress.nix
index 5d2e775d4521..03d5634854a3 100644
--- a/nixos/modules/services/web-apps/wordpress.nix
+++ b/nixos/modules/services/web-apps/wordpress.nix
@@ -104,12 +104,7 @@ let
   siteOpts = { lib, name, config, ... }:
     {
       options = {
-        package = mkOption {
-          type = types.package;
-          default = pkgs.wordpress;
-          defaultText = literalExpression "pkgs.wordpress";
-          description = lib.mdDoc "Which WordPress package to use.";
-        };
+        package = mkPackageOption pkgs "wordpress" { };
 
         uploadsDir = mkOption {
           type = types.path;
diff --git a/nixos/modules/services/web-apps/youtrack.nix b/nixos/modules/services/web-apps/youtrack.nix
index 09a2b9e965c0..79e1d12e0abb 100644
--- a/nixos/modules/services/web-apps/youtrack.nix
+++ b/nixos/modules/services/web-apps/youtrack.nix
@@ -54,14 +54,7 @@ in
       type = types.attrsOf types.str;
     };
 
-    package = mkOption {
-      description = lib.mdDoc ''
-        Package to use.
-      '';
-      type = types.package;
-      default = pkgs.youtrack;
-      defaultText = literalExpression "pkgs.youtrack";
-    };
+    package = mkPackageOption pkgs "youtrack" { };
 
     port = mkOption {
       description = lib.mdDoc ''
diff --git a/nixos/modules/services/web-apps/zabbix.nix b/nixos/modules/services/web-apps/zabbix.nix
index 2cea7e7cea72..4f6d7e4e6c1c 100644
--- a/nixos/modules/services/web-apps/zabbix.nix
+++ b/nixos/modules/services/web-apps/zabbix.nix
@@ -2,7 +2,7 @@
 
 let
 
-  inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types;
+  inherit (lib) mkDefault mkEnableOption mkPackageOption mkForce mkIf mkMerge mkOption types;
   inherit (lib) literalExpression mapAttrs optionalString versionAtLeast;
 
   cfg = config.services.zabbixWeb;
@@ -42,12 +42,7 @@ in
     zabbixWeb = {
       enable = mkEnableOption (lib.mdDoc "the Zabbix web interface");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.zabbix.web;
-        defaultText = literalExpression "zabbix.web";
-        description = lib.mdDoc "Which Zabbix package to use.";
-      };
+      package = mkPackageOption pkgs [ "zabbix" "web" ] { };
 
       server = {
         port = mkOption {
diff --git a/nixos/modules/services/web-servers/agate.nix b/nixos/modules/services/web-servers/agate.nix
index a0c8a8c94ee5..dce425035ff7 100644
--- a/nixos/modules/services/web-servers/agate.nix
+++ b/nixos/modules/services/web-servers/agate.nix
@@ -10,12 +10,7 @@ in
     services.agate = {
       enable = mkEnableOption (lib.mdDoc "Agate Server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.agate;
-        defaultText = literalExpression "pkgs.agate";
-        description = lib.mdDoc "The package to use";
-      };
+      package = mkPackageOption pkgs "agate" { };
 
       addresses = mkOption {
         type = types.listOf types.str;
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 588f5ee4d003..016e4885a095 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -406,14 +406,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "the Apache HTTP Server");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.apacheHttpd;
-        defaultText = literalExpression "pkgs.apacheHttpd";
-        description = lib.mdDoc ''
-          Overridable attribute of the Apache HTTP Server package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "apacheHttpd" { };
 
       configFile = mkOption {
         type = types.path;
@@ -557,14 +550,7 @@ in
         description = lib.mdDoc "Whether to enable the PHP module.";
       };
 
-      phpPackage = mkOption {
-        type = types.package;
-        default = pkgs.php;
-        defaultText = literalExpression "pkgs.php";
-        description = lib.mdDoc ''
-          Overridable attribute of the PHP package to use.
-        '';
-      };
+      phpPackage = mkPackageOption pkgs "php" { };
 
       enablePerl = mkOption {
         type = types.bool;
diff --git a/nixos/modules/services/web-servers/caddy/default.nix b/nixos/modules/services/web-servers/caddy/default.nix
index cc89553fbb75..497aa9ba956e 100644
--- a/nixos/modules/services/web-servers/caddy/default.nix
+++ b/nixos/modules/services/web-servers/caddy/default.nix
@@ -94,14 +94,7 @@ in
       '';
     };
 
-    package = mkOption {
-      default = pkgs.caddy;
-      defaultText = literalExpression "pkgs.caddy";
-      type = types.package;
-      description = lib.mdDoc ''
-        Caddy package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "caddy" { };
 
     dataDir = mkOption {
       type = types.path;
diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix
index eaa113c0d52c..3a33137b27d2 100644
--- a/nixos/modules/services/web-servers/lighttpd/default.nix
+++ b/nixos/modules/services/web-servers/lighttpd/default.nix
@@ -135,14 +135,7 @@ in
         '';
       };
 
-      package = mkOption {
-        default = pkgs.lighttpd;
-        defaultText = lib.literalExpression "pkgs.lighttpd";
-        type = types.package;
-        description = lib.mdDoc ''
-          lighttpd package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "lighttpd" { };
 
       port = mkOption {
         default = 80;
diff --git a/nixos/modules/services/web-servers/minio.nix b/nixos/modules/services/web-servers/minio.nix
index 0bc7421a0e32..6431db250476 100644
--- a/nixos/modules/services/web-servers/minio.nix
+++ b/nixos/modules/services/web-servers/minio.nix
@@ -85,12 +85,7 @@ in
       description = lib.mdDoc "Enable or disable access to web UI.";
     };
 
-    package = mkOption {
-      default = pkgs.minio;
-      defaultText = literalExpression "pkgs.minio";
-      type = types.package;
-      description = lib.mdDoc "Minio package to use.";
-    };
+    package = mkPackageOption pkgs "minio" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/web-servers/phpfpm/default.nix b/nixos/modules/services/web-servers/phpfpm/default.nix
index 0bd1d5b29b31..4132a97b9543 100644
--- a/nixos/modules/services/web-servers/phpfpm/default.nix
+++ b/nixos/modules/services/web-servers/phpfpm/default.nix
@@ -179,14 +179,7 @@ in {
         '';
       };
 
-      phpPackage = mkOption {
-        type = types.package;
-        default = pkgs.php;
-        defaultText = literalExpression "pkgs.php";
-        description = lib.mdDoc ''
-          The PHP package to use for running the PHP-FPM service.
-        '';
-      };
+      phpPackage = mkPackageOption pkgs "php" { };
 
       phpOptions = mkOption {
         type = types.lines;
diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix
index 30d6b99fcfda..8c3b9c9269a1 100644
--- a/nixos/modules/services/web-servers/tomcat.nix
+++ b/nixos/modules/services/web-servers/tomcat.nix
@@ -17,7 +17,9 @@ in
     services.tomcat = {
       enable = lib.mkEnableOption (lib.mdDoc "Apache Tomcat");
 
-      package = lib.mkPackageOptionMD pkgs "tomcat9" { };
+      package = lib.mkPackageOption pkgs "tomcat9" {
+        example = "tomcat10";
+      };
 
       purifyOnStart = lib.mkOption {
         type = lib.types.bool;
@@ -151,7 +153,7 @@ in
         description = lib.mdDoc "Whether to enable logging per virtual host.";
       };
 
-      jdk = lib.mkPackageOptionMD pkgs "jdk" { };
+      jdk = lib.mkPackageOption pkgs "jdk" { };
 
       axis2 = {
         enable = lib.mkEnableOption "Apache Axis2 container";
diff --git a/nixos/modules/services/web-servers/traefik.nix b/nixos/modules/services/web-servers/traefik.nix
index 42fb95a52200..cc2c680b3342 100644
--- a/nixos/modules/services/web-servers/traefik.nix
+++ b/nixos/modules/services/web-servers/traefik.nix
@@ -126,12 +126,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      default = pkgs.traefik;
-      defaultText = literalExpression "pkgs.traefik";
-      type = types.package;
-      description = lib.mdDoc "Traefik package to use.";
-    };
+    package = mkPackageOption pkgs "traefik" { };
 
     environmentFiles = mkOption {
       default = [];
diff --git a/nixos/modules/services/web-servers/unit/default.nix b/nixos/modules/services/web-servers/unit/default.nix
index 1515779c9064..a5f1a872ce81 100644
--- a/nixos/modules/services/web-servers/unit/default.nix
+++ b/nixos/modules/services/web-servers/unit/default.nix
@@ -11,12 +11,7 @@ in {
   options = {
     services.unit = {
       enable = mkEnableOption (lib.mdDoc "Unit App Server");
-      package = mkOption {
-        type = types.package;
-        default = pkgs.unit;
-        defaultText = literalExpression "pkgs.unit";
-        description = lib.mdDoc "Unit package to use.";
-      };
+      package = mkPackageOption pkgs "unit" { };
       user = mkOption {
         type = types.str;
         default = "unit";
diff --git a/nixos/modules/services/web-servers/varnish/default.nix b/nixos/modules/services/web-servers/varnish/default.nix
index d7f19be0cec4..857dd64c01be 100644
--- a/nixos/modules/services/web-servers/varnish/default.nix
+++ b/nixos/modules/services/web-servers/varnish/default.nix
@@ -15,14 +15,7 @@ in
 
       enableConfigCheck = mkEnableOption (lib.mdDoc "checking the config during build time") // { default = true; };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.varnish;
-        defaultText = literalExpression "pkgs.varnish";
-        description = lib.mdDoc ''
-          The package to use
-        '';
-      };
+      package = mkPackageOption pkgs "varnish" { };
 
       http_address = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/x11/desktop-managers/deepin.nix b/nixos/modules/services/x11/desktop-managers/deepin.nix
index f70e316a2309..7fdd50b1ed26 100644
--- a/nixos/modules/services/x11/desktop-managers/deepin.nix
+++ b/nixos/modules/services/x11/desktop-managers/deepin.nix
@@ -38,8 +38,8 @@ in
 
   config = mkIf cfg.enable
     {
-      services.xserver.displayManager.sessionPackages = [ pkgs.deepin.startdde ];
-      services.xserver.displayManager.defaultSession = mkDefault "deepin";
+      services.xserver.displayManager.sessionPackages = [ pkgs.deepin.dde-session ];
+      services.xserver.displayManager.defaultSession = mkDefault "dde-x11";
 
       # Update the DBus activation environment after launching the desktop manager.
       services.xserver.displayManager.sessionCommands = ''
@@ -93,6 +93,9 @@ in
         "/lib/dde-file-manager"
         "/share/backgrounds"
         "/share/wallpapers"
+        "/share/dde-daemon"
+        "/share/dsg"
+        "/share/deepin-themes"
       ];
 
       environment.etc = {
@@ -138,19 +141,25 @@ in
             libsForQt5.kde-gtk-config # deepin-api/gtk-thumbnailer need
             libsForQt5.kglobalaccel
             xsettingsd # lightdm-deepin-greeter
+            dtkcommon
+            dtkcore
+            dtkgui
+            dtkwidget
+            dtkdeclarative
             qt5platform-plugins
             deepin-pw-check
             deepin-turbo
 
             dde-account-faces
             deepin-icon-theme
+            deepin-desktop-theme
             deepin-sound-theme
             deepin-gtk-theme
             deepin-wallpapers
 
             startdde
             dde-dock
-            dde-launcher
+            dde-launchpad
             dde-session-ui
             dde-session-shell
             dde-file-manager
@@ -162,8 +171,12 @@ in
             dpa-ext-gnomekeyring
             deepin-desktop-schemas
             deepin-terminal
-            dde-kwin
             deepin-kwin
+            dde-session
+            dde-widgets
+            dde-appearance
+            dde-application-manager
+            deepin-service-manager
           ];
           optionalPackages = [
             onboard # dde-dock plugin
@@ -187,24 +200,33 @@ in
 
       services.dbus.packages = with pkgs.deepin; [
         dde-dock
-        dde-launcher
+        dde-launchpad
         dde-session-ui
         dde-session-shell
         dde-file-manager
         dde-control-center
         dde-calendar
         dde-clipboard
-        dde-kwin
         deepin-kwin
         deepin-pw-check
+        dde-widgets
+        dde-session
+        dde-appearance
+        dde-application-manager
+        deepin-service-manager
       ];
 
       systemd.packages = with pkgs.deepin; [
-        dde-launcher
+        dde-launchpad
         dde-file-manager
         dde-calendar
         dde-clipboard
         deepin-kwin
+        dde-appearance
+        dde-widgets
+        dde-session
+        dde-application-manager
+        deepin-service-manager
       ];
     };
 }
diff --git a/nixos/modules/services/x11/desktop-managers/kodi.nix b/nixos/modules/services/x11/desktop-managers/kodi.nix
index 43904cd00e84..452f571d49e6 100644
--- a/nixos/modules/services/x11/desktop-managers/kodi.nix
+++ b/nixos/modules/services/x11/desktop-managers/kodi.nix
@@ -15,14 +15,8 @@ in
         description = lib.mdDoc "Enable the kodi multimedia center.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.kodi;
-        defaultText = literalExpression "pkgs.kodi";
-        example = literalExpression "pkgs.kodi.withPackages (p: with p; [ jellyfin pvr-iptvsimple vfs-sftp ])";
-        description = lib.mdDoc ''
-          Package that should be used for Kodi.
-        '';
+      package = mkPackageOption pkgs "kodi" {
+        example = "kodi.withPackages (p: with p; [ jellyfin pvr-iptvsimple vfs-sftp ])";
       };
     };
   };
diff --git a/nixos/modules/services/x11/desktop-managers/phosh.nix b/nixos/modules/services/x11/desktop-managers/phosh.nix
index e4cd9fd99e40..5392ab73aeb8 100644
--- a/nixos/modules/services/x11/desktop-managers/phosh.nix
+++ b/nixos/modules/services/x11/desktop-managers/phosh.nix
@@ -135,15 +135,7 @@ in
         description = lib.mdDoc "Enable the Phone Shell.";
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.phosh;
-        defaultText = literalExpression "pkgs.phosh";
-        example = literalExpression "pkgs.phosh";
-        description = lib.mdDoc ''
-          Package that should be used for Phosh.
-        '';
-      };
+      package = mkPackageOption pkgs "phosh" { };
 
       user = mkOption {
         description = lib.mdDoc "The user to run the Phosh service.";
diff --git a/nixos/modules/services/x11/desktop-managers/retroarch.nix b/nixos/modules/services/x11/desktop-managers/retroarch.nix
index 5552f37612a2..9db637191b54 100644
--- a/nixos/modules/services/x11/desktop-managers/retroarch.nix
+++ b/nixos/modules/services/x11/desktop-managers/retroarch.nix
@@ -8,12 +8,8 @@ in {
   options.services.xserver.desktopManager.retroarch = {
     enable = mkEnableOption (lib.mdDoc "RetroArch");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.retroarch;
-      defaultText = literalExpression "pkgs.retroarch";
-      example = literalExpression "pkgs.retroarch-full";
-      description = lib.mdDoc "RetroArch package to use.";
+    package = mkPackageOption pkgs "retroarch" {
+      example = "retroarch-full";
     };
 
     extraArgs = mkOption {
diff --git a/nixos/modules/services/x11/redshift.nix b/nixos/modules/services/x11/redshift.nix
index 3eb9e28edae9..80605eb11407 100644
--- a/nixos/modules/services/x11/redshift.nix
+++ b/nixos/modules/services/x11/redshift.nix
@@ -73,14 +73,7 @@ in {
       };
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.redshift;
-      defaultText = literalExpression "pkgs.redshift";
-      description = lib.mdDoc ''
-        redshift derivation to use.
-      '';
-    };
+    package = mkPackageOption pkgs "redshift" { };
 
     executable = mkOption {
       type = types.str;
diff --git a/nixos/modules/services/x11/touchegg.nix b/nixos/modules/services/x11/touchegg.nix
index f1103c054c57..54918245f156 100644
--- a/nixos/modules/services/x11/touchegg.nix
+++ b/nixos/modules/services/x11/touchegg.nix
@@ -13,12 +13,7 @@ in {
   options.services.touchegg = {
     enable = mkEnableOption (lib.mdDoc "touchegg, a multi-touch gesture recognizer");
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.touchegg;
-      defaultText = literalExpression "pkgs.touchegg";
-      description = lib.mdDoc "touchegg derivation to use.";
-    };
+    package = mkPackageOption pkgs "touchegg" { };
   };
 
   ###### implementation
diff --git a/nixos/modules/services/x11/unclutter-xfixes.nix b/nixos/modules/services/x11/unclutter-xfixes.nix
index 4a35176c5833..9255c8124788 100644
--- a/nixos/modules/services/x11/unclutter-xfixes.nix
+++ b/nixos/modules/services/x11/unclutter-xfixes.nix
@@ -13,12 +13,7 @@ in {
       default = false;
     };
 
-    package = mkOption {
-      description = lib.mdDoc "unclutter-xfixes derivation to use.";
-      type = types.package;
-      default = pkgs.unclutter-xfixes;
-      defaultText = literalExpression "pkgs.unclutter-xfixes";
-    };
+    package = mkPackageOption pkgs "unclutter-xfixes" { };
 
     timeout = mkOption {
       description = lib.mdDoc "Number of seconds before the cursor is marked inactive.";
diff --git a/nixos/modules/services/x11/unclutter.nix b/nixos/modules/services/x11/unclutter.nix
index 039214a575a7..ecf7e2668cec 100644
--- a/nixos/modules/services/x11/unclutter.nix
+++ b/nixos/modules/services/x11/unclutter.nix
@@ -13,12 +13,7 @@ in {
       default = false;
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.unclutter;
-      defaultText = literalExpression "pkgs.unclutter";
-      description = lib.mdDoc "unclutter derivation to use.";
-    };
+    package = mkPackageOption pkgs "unclutter" { };
 
     keystroke = mkOption {
       description = lib.mdDoc "Wait for a keystroke before hiding the cursor";
diff --git a/nixos/modules/services/x11/urxvtd.nix b/nixos/modules/services/x11/urxvtd.nix
index fedcb6c7293e..bab9f43b0952 100644
--- a/nixos/modules/services/x11/urxvtd.nix
+++ b/nixos/modules/services/x11/urxvtd.nix
@@ -17,14 +17,7 @@ in {
       '';
     };
 
-    package = mkOption {
-      default = pkgs.rxvt-unicode;
-      defaultText = literalExpression "pkgs.rxvt-unicode";
-      description = lib.mdDoc ''
-        Package to install. Usually pkgs.rxvt-unicode.
-      '';
-      type = types.package;
-    };
+    package = mkPackageOption pkgs "rxvt-unicode" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/services/x11/window-managers/awesome.nix b/nixos/modules/services/x11/window-managers/awesome.nix
index c1231d3fbf38..0478f326825f 100644
--- a/nixos/modules/services/x11/window-managers/awesome.nix
+++ b/nixos/modules/services/x11/window-managers/awesome.nix
@@ -30,12 +30,7 @@ in
         example = literalExpression "[ pkgs.luaPackages.vicious ]";
       };
 
-      package = mkOption {
-        default = null;
-        type = types.nullOr types.package;
-        description = lib.mdDoc "Package to use for running the Awesome WM.";
-        apply = pkg: if pkg == null then pkgs.awesome else pkg;
-      };
+      package = mkPackageOption pkgs "awesome" { };
 
       noArgb = mkOption {
         default = false;
diff --git a/nixos/modules/services/x11/window-managers/bspwm.nix b/nixos/modules/services/x11/window-managers/bspwm.nix
index c403f744cd43..cd8852cdfdee 100644
--- a/nixos/modules/services/x11/window-managers/bspwm.nix
+++ b/nixos/modules/services/x11/window-managers/bspwm.nix
@@ -11,14 +11,8 @@ in
     services.xserver.windowManager.bspwm = {
       enable = mkEnableOption (lib.mdDoc "bspwm");
 
-      package = mkOption {
-        type        = types.package;
-        default     = pkgs.bspwm;
-        defaultText = literalExpression "pkgs.bspwm";
-        example     = literalExpression "pkgs.bspwm-unstable";
-        description = lib.mdDoc ''
-          bspwm package to use.
-        '';
+      package = mkPackageOption pkgs "bspwm" {
+        example = "bspwm-unstable";
       };
       configFile = mkOption {
         type        = with types; nullOr path;
@@ -31,14 +25,8 @@ in
       };
 
       sxhkd = {
-        package = mkOption {
-          type        = types.package;
-          default     = pkgs.sxhkd;
-          defaultText = literalExpression "pkgs.sxhkd";
-          example     = literalExpression "pkgs.sxhkd-unstable";
-          description = lib.mdDoc ''
-            sxhkd package to use.
-          '';
+        package = mkPackageOption pkgs "sxhkd" {
+          example = "sxhkd-unstable";
         };
         configFile = mkOption {
           type        = with types; nullOr path;
diff --git a/nixos/modules/services/x11/window-managers/clfswm.nix b/nixos/modules/services/x11/window-managers/clfswm.nix
index f2e4c2f91c9d..4d47c50c87ef 100644
--- a/nixos/modules/services/x11/window-managers/clfswm.nix
+++ b/nixos/modules/services/x11/window-managers/clfswm.nix
@@ -10,14 +10,7 @@ in
   options = {
     services.xserver.windowManager.clfswm = {
       enable = mkEnableOption (lib.mdDoc "clfswm");
-      package = mkOption {
-        type        = types.package;
-        default     = pkgs.lispPackages.clfswm;
-        defaultText = literalExpression "pkgs.lispPackages.clfswm";
-        description = lib.mdDoc ''
-          clfswm package to use.
-        '';
-      };
+      package = mkPackageOption pkgs [ "lispPackages" "clfswm" ] { };
     };
   };
 
diff --git a/nixos/modules/services/x11/window-managers/dwm.nix b/nixos/modules/services/x11/window-managers/dwm.nix
index 82900fd30540..b5c7d37653ed 100644
--- a/nixos/modules/services/x11/window-managers/dwm.nix
+++ b/nixos/modules/services/x11/window-managers/dwm.nix
@@ -15,11 +15,8 @@ in
   options = {
     services.xserver.windowManager.dwm = {
       enable = mkEnableOption (lib.mdDoc "dwm");
-      package = mkOption {
-        type        = types.package;
-        default     = pkgs.dwm;
-        defaultText = literalExpression "pkgs.dwm";
-        example     = literalExpression ''
+      package = mkPackageOption pkgs "dwm" {
+        example = ''
           pkgs.dwm.overrideAttrs (oldAttrs: rec {
             patches = [
               (super.fetchpatch {
@@ -29,9 +26,6 @@ in
             ];
           })
         '';
-        description = lib.mdDoc ''
-          dwm package to use.
-        '';
       };
     };
   };
diff --git a/nixos/modules/services/x11/window-managers/herbstluftwm.nix b/nixos/modules/services/x11/window-managers/herbstluftwm.nix
index 93705ada116d..16ebc2bfe1d3 100644
--- a/nixos/modules/services/x11/window-managers/herbstluftwm.nix
+++ b/nixos/modules/services/x11/window-managers/herbstluftwm.nix
@@ -11,14 +11,7 @@ in
     services.xserver.windowManager.herbstluftwm = {
       enable = mkEnableOption (lib.mdDoc "herbstluftwm");
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.herbstluftwm;
-        defaultText = literalExpression "pkgs.herbstluftwm";
-        description = lib.mdDoc ''
-          Herbstluftwm package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "herbstluftwm" { };
 
       configFile = mkOption {
         default     = null;
diff --git a/nixos/modules/services/x11/window-managers/i3.nix b/nixos/modules/services/x11/window-managers/i3.nix
index 5bb73cd0bfb1..7163e4b5abb5 100644
--- a/nixos/modules/services/x11/window-managers/i3.nix
+++ b/nixos/modules/services/x11/window-managers/i3.nix
@@ -27,14 +27,7 @@ in
       '';
     };
 
-    package = mkOption {
-      type        = types.package;
-      default     = pkgs.i3;
-      defaultText = literalExpression "pkgs.i3";
-      description = lib.mdDoc ''
-        i3 package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "i3" { };
 
     extraPackages = mkOption {
       type = with types; listOf package;
diff --git a/nixos/modules/services/x11/window-managers/ragnarwm.nix b/nixos/modules/services/x11/window-managers/ragnarwm.nix
index 0843b872dba5..7242c8b1324c 100644
--- a/nixos/modules/services/x11/window-managers/ragnarwm.nix
+++ b/nixos/modules/services/x11/window-managers/ragnarwm.nix
@@ -11,14 +11,7 @@ in
   options = {
     services.xserver.windowManager.ragnarwm = {
       enable = mkEnableOption (lib.mdDoc "ragnarwm");
-      package = mkOption {
-        type = types.package;
-        default = pkgs.ragnarwm;
-        defaultText = literalExpression "pkgs.ragnarwm";
-        description = lib.mdDoc ''
-          The ragnar package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "ragnarwm" { };
     };
   };
 
diff --git a/nixos/modules/system/boot/unl0kr.nix b/nixos/modules/system/boot/unl0kr.nix
new file mode 100644
index 000000000000..8d9af37382e0
--- /dev/null
+++ b/nixos/modules/system/boot/unl0kr.nix
@@ -0,0 +1,89 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.boot.initrd.unl0kr;
+in
+{
+  options.boot.initrd.unl0kr = {
+    enable = lib.mkEnableOption (lib.mdDoc "unl0kr in initrd") // {
+      description = lib.mdDoc ''
+        Whether to enable the unl0kr on-screen keyboard in initrd to unlock LUKS.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    meta.maintainers = with lib.maintainers; [ tomfitzhenry ];
+    assertions = [
+      {
+        assertion = cfg.enable -> config.boot.initrd.systemd.enable;
+        message = "boot.initrd.unl0kr is only supported with boot.initrd.systemd.";
+      }
+    ];
+
+    boot.initrd.systemd = {
+      storePaths = with pkgs; [
+        "${pkgs.gnugrep}/bin/grep"
+        libinput
+        xkeyboard_config
+        "${config.boot.initrd.systemd.package}/lib/systemd/systemd-reply-password"
+        "${pkgs.unl0kr}/bin/unl0kr"
+      ];
+      services = {
+        unl0kr-ask-password = {
+          description = "Forward Password Requests to unl0kr";
+          conflicts = [
+            "emergency.service"
+            "initrd-switch-root.target"
+            "shutdown.target"
+          ];
+          unitConfig.DefaultDependencies = false;
+          after = [
+            "systemd-vconsole-setup.service"
+            "udev.service"
+          ];
+          before = [
+            "shutdown.target"
+          ];
+          script = ''
+            # This script acts as a Password Agent: https://systemd.io/PASSWORD_AGENTS/
+
+            DIR=/run/systemd/ask-password/
+            # If a user has multiple encrypted disks, the requests might come in different times,
+            # so make sure to answer as many requests as we can. Once boot succeeds, other
+            # password agents will be responsible for watching for requests.
+            while [ -d $DIR ] && [ "$(ls -A $DIR/ask.*)" ];
+            do
+              for file in `ls $DIR/ask.*`; do
+                socket="$(cat "$file" | ${pkgs.gnugrep}/bin/grep "Socket=" | cut -d= -f2)"
+                ${pkgs.unl0kr}/bin/unl0kr | ${config.boot.initrd.systemd.package}/lib/systemd/systemd-reply-password 1 "$socket"
+              done
+            done
+          '';
+        };
+      };
+
+      paths = {
+        unl0kr-ask-password = {
+          description = "Forward Password Requests to unl0kr";
+          conflicts = [
+            "emergency.service"
+            "initrd-switch-root.target"
+            "shutdown.target"
+          ];
+          unitConfig.DefaultDependencies = false;
+          before = [
+            "shutdown.target"
+            "paths.target"
+            "cryptsetup.target"
+          ];
+          wantedBy = [ "sysinit.target" ];
+          pathConfig = {
+            DirectoryNotEmpty = "/run/systemd/ask-password";
+            MakeDirectory = true;
+          };
+        };
+      };
+    };
+  };
+}
diff --git a/nixos/modules/virtualisation/docker-rootless.nix b/nixos/modules/virtualisation/docker-rootless.nix
index f4e4bdc0963a..1cdb98b704ce 100644
--- a/nixos/modules/virtualisation/docker-rootless.nix
+++ b/nixos/modules/virtualisation/docker-rootless.nix
@@ -47,14 +47,7 @@ in
       '';
     };
 
-    package = mkOption {
-      default = pkgs.docker;
-      defaultText = literalExpression "pkgs.docker";
-      type = types.package;
-      description = lib.mdDoc ''
-        Docker package to be used in the module.
-      '';
-    };
+    package = mkPackageOption pkgs "docker" { };
   };
 
   ###### implementation
diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix
index 6fe460316091..b0d61ee06091 100644
--- a/nixos/modules/virtualisation/docker.nix
+++ b/nixos/modules/virtualisation/docker.nix
@@ -150,14 +150,7 @@ in
       };
     };
 
-    package = mkOption {
-      default = pkgs.docker;
-      defaultText = literalExpression "pkgs.docker";
-      type = types.package;
-      description = lib.mdDoc ''
-        Docker package to be used in the module.
-      '';
-    };
+    package = mkPackageOption pkgs "docker" { };
 
     extraPackages = mkOption {
       type = types.listOf types.package;
diff --git a/nixos/modules/virtualisation/ecs-agent.nix b/nixos/modules/virtualisation/ecs-agent.nix
index dd87df9a2780..76bdccca9872 100644
--- a/nixos/modules/virtualisation/ecs-agent.nix
+++ b/nixos/modules/virtualisation/ecs-agent.nix
@@ -8,12 +8,7 @@ in {
   options.services.ecs-agent = {
     enable = mkEnableOption (lib.mdDoc "Amazon ECS agent");
 
-    package = mkOption {
-      type = types.path;
-      description = lib.mdDoc "The ECS agent package to use";
-      default = pkgs.ecs-agent;
-      defaultText = literalExpression "pkgs.ecs-agent";
-    };
+    package = mkPackageOption pkgs "ecs-agent" { };
 
     extra-environment = mkOption {
       type = types.attrsOf types.str;
diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix
index 708c577ec1ed..fa5947e546c1 100644
--- a/nixos/modules/virtualisation/libvirtd.nix
+++ b/nixos/modules/virtualisation/libvirtd.nix
@@ -64,25 +64,14 @@ let
         '';
       };
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.swtpm;
-        defaultText = literalExpression "pkgs.swtpm";
-        description = lib.mdDoc ''
-          swtpm package to use.
-        '';
-      };
+      package = mkPackageOption pkgs "swtpm" { };
     };
   };
 
   qemuModule = types.submodule {
     options = {
-      package = mkOption {
-        type = types.package;
-        default = pkgs.qemu;
-        defaultText = literalExpression "pkgs.qemu";
-        description = lib.mdDoc ''
-          Qemu package to use with libvirt.
+      package = mkPackageOption pkgs "qemu" {
+        extraDescription = ''
           `pkgs.qemu` can emulate alien architectures (e.g. aarch64 on x86)
           `pkgs.qemu_kvm` saves disk space allowing to emulate only host architectures.
         '';
@@ -224,14 +213,7 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.libvirt;
-      defaultText = literalExpression "pkgs.libvirt";
-      description = lib.mdDoc ''
-        libvirt package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "libvirt" { };
 
     extraConfig = mkOption {
       type = types.lines;
diff --git a/nixos/modules/virtualisation/openvswitch.nix b/nixos/modules/virtualisation/openvswitch.nix
index 32646f60f8e0..a968c732f8f7 100644
--- a/nixos/modules/virtualisation/openvswitch.nix
+++ b/nixos/modules/virtualisation/openvswitch.nix
@@ -28,14 +28,7 @@ in {
         '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.openvswitch;
-      defaultText = literalExpression "pkgs.openvswitch";
-      description = lib.mdDoc ''
-        Open vSwitch package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "openvswitch" { };
   };
 
   config = mkIf cfg.enable (let
diff --git a/nixos/modules/virtualisation/qemu-guest-agent.nix b/nixos/modules/virtualisation/qemu-guest-agent.nix
index 650fb2419160..aeab0ceac3cc 100644
--- a/nixos/modules/virtualisation/qemu-guest-agent.nix
+++ b/nixos/modules/virtualisation/qemu-guest-agent.nix
@@ -12,12 +12,7 @@ in {
         default = false;
         description = lib.mdDoc "Whether to enable the qemu guest agent.";
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.qemu_kvm.ga;
-        defaultText = literalExpression "pkgs.qemu_kvm.ga";
-        description = lib.mdDoc "The QEMU guest agent package.";
-      };
+      package = mkPackageOption pkgs [ "qemu_kvm" "ga" ] { };
   };
 
   config = mkIf cfg.enable (
diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix
index 9741ea090f79..50a8f8189590 100644
--- a/nixos/modules/virtualisation/virtualbox-host.nix
+++ b/nixos/modules/virtualisation/virtualbox-host.nix
@@ -40,14 +40,7 @@ in
       '';
     };
 
-    package = mkOption {
-      type = types.package;
-      default = pkgs.virtualbox;
-      defaultText = literalExpression "pkgs.virtualbox";
-      description = lib.mdDoc ''
-        Which VirtualBox package to use.
-      '';
-    };
+    package = mkPackageOption pkgs "virtualbox" { };
 
     addNetworkInterface = mkOption {
       type = types.bool;
diff --git a/nixos/modules/virtualisation/vmware-host.nix b/nixos/modules/virtualisation/vmware-host.nix
index 4b2dc28aeac7..1eaa896fe096 100644
--- a/nixos/modules/virtualisation/vmware-host.nix
+++ b/nixos/modules/virtualisation/vmware-host.nix
@@ -37,12 +37,7 @@ in
           :::
         '';
       };
-      package = mkOption {
-        type = types.package;
-        default = pkgs.vmware-workstation;
-        defaultText = literalExpression "pkgs.vmware-workstation";
-        description = lib.mdDoc "VMware host virtualisation package to use";
-      };
+      package = mkPackageOption pkgs "vmware-workstation" { };
       extraPackages = mkOption {
         type = with types; listOf package;
         default = with pkgs; [ ];
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 1e11cc220805..480439c2a25e 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -813,6 +813,7 @@ in {
   systemd-initrd-luks-empty-passphrase = handleTest ./initrd-luks-empty-passphrase.nix { systemdStage1 = true; };
   systemd-initrd-luks-password = handleTest ./systemd-initrd-luks-password.nix {};
   systemd-initrd-luks-tpm2 = handleTest ./systemd-initrd-luks-tpm2.nix {};
+  systemd-initrd-luks-unl0kr = handleTest ./systemd-initrd-luks-unl0kr.nix {};
   systemd-initrd-modprobe = handleTest ./systemd-initrd-modprobe.nix {};
   systemd-initrd-shutdown = handleTest ./systemd-shutdown.nix { systemdStage1 = true; };
   systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {};
diff --git a/nixos/tests/deepin.nix b/nixos/tests/deepin.nix
index 7b2e2430f31c..d3ce79a535c1 100644
--- a/nixos/tests/deepin.nix
+++ b/nixos/tests/deepin.nix
@@ -36,12 +36,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
       with subtest("Check that logging in has given the user ownership of devices"):
           machine.succeed("getfacl -p /dev/snd/timer | grep -q ${user.name}")
 
-      with subtest("Check if DDE wm chooser actually start"):
-          machine.wait_until_succeeds("pgrep -f dde-wm-chooser")
-          machine.wait_for_window("dde-wm-chooser")
-          machine.execute("pkill dde-wm-chooser")
-
-
       with subtest("Check if Deepin session components actually start"):
           machine.wait_until_succeeds("pgrep -f dde-session-daemon")
           machine.wait_for_window("dde-session-daemon")
diff --git a/nixos/tests/jitsi-meet.nix b/nixos/tests/jitsi-meet.nix
index c39cd19e1f0a..fc6654f2c076 100644
--- a/nixos/tests/jitsi-meet.nix
+++ b/nixos/tests/jitsi-meet.nix
@@ -24,10 +24,23 @@ import ./make-test-python.nix ({ pkgs, ... }: {
       security.acme.acceptTerms = true;
       security.acme.defaults.email = "me@example.org";
       security.acme.defaults.server = "https://example.com"; # self-signed only
+
+      specialisation.caddy = {
+        inheritParentConfig = true;
+        configuration = {
+          services.jitsi-meet = {
+            caddy.enable = true;
+            nginx.enable = false;
+          };
+          services.caddy.virtualHosts.${config.services.jitsi-meet.hostName}.extraConfig = ''
+            tls internal
+          '';
+        };
+      };
     };
   };
 
-  testScript = ''
+  testScript = { nodes, ... }: ''
     server.wait_for_unit("jitsi-videobridge2.service")
     server.wait_for_unit("jicofo.service")
     server.wait_for_unit("nginx.service")
@@ -41,6 +54,15 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     )
 
     client.wait_for_unit("network.target")
-    assert "<title>Jitsi Meet</title>" in client.succeed("curl -sSfkL http://server/")
+
+    def client_curl():
+        assert "<title>Jitsi Meet</title>" in client.succeed("curl -sSfkL http://server/")
+
+    client_curl()
+
+    with subtest("Testing backup service"):
+        server.succeed("${nodes.server.system.build.toplevel}/specialisation/caddy/bin/switch-to-configuration test")
+        server.wait_for_unit("caddy.service")
+        client_curl()
   '';
 })
diff --git a/nixos/tests/lanraragi.nix b/nixos/tests/lanraragi.nix
index f513ac9d252b..7a4a1a489bdf 100644
--- a/nixos/tests/lanraragi.nix
+++ b/nixos/tests/lanraragi.nix
@@ -10,19 +10,17 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
       services.lanraragi = {
         enable = true;
         passwordFile = pkgs.writeText "lrr-test-pass" ''
-          ultra-secure-password
+          Ultra-secure-p@ssword-"with-spec1al\chars
         '';
         port = 4000;
         redis = {
           port = 4001;
           passwordFile = pkgs.writeText "redis-lrr-test-pass" ''
-            still-a-very-secure-password
+            123-redis-PASS
           '';
         };
       };
     };
-
-
   };
 
   testScript = ''
@@ -34,7 +32,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
 
     machine2.wait_for_unit("lanraragi.service")
     machine2.wait_until_succeeds("curl -f localhost:4000")
-    machine2.succeed("[ $(curl -o /dev/null -X post 'http://localhost:4000/login' --data-raw 'password=ultra-secure-password' -w '%{http_code}') -eq 302 ]")
+    machine2.succeed("[ $(curl -o /dev/null -X post 'http://localhost:4000/login' --data-raw 'password=Ultra-secure-p@ssword-\"with-spec1al\\chars' -w '%{http_code}') -eq 302 ]")
   '';
 })
 
diff --git a/nixos/tests/matrix/synapse.nix b/nixos/tests/matrix/synapse.nix
index 98b077469192..8c10a575ffbd 100644
--- a/nixos/tests/matrix/synapse.nix
+++ b/nixos/tests/matrix/synapse.nix
@@ -1,31 +1,15 @@
 import ../make-test-python.nix ({ pkgs, ... } : let
 
-
-  runWithOpenSSL = file: cmd: pkgs.runCommand file {
-    buildInputs = [ pkgs.openssl ];
-  } cmd;
-
-
-  ca_key = runWithOpenSSL "ca-key.pem" "openssl genrsa -out $out 2048";
-  ca_pem = runWithOpenSSL "ca.pem" ''
-    openssl req \
-      -x509 -new -nodes -key ${ca_key} \
-      -days 10000 -out $out -subj "/CN=snakeoil-ca"
+  ca_key = mailerCerts.ca.key;
+  ca_pem = mailerCerts.ca.cert;
+
+  bundle = pkgs.runCommand "bundle" {
+    nativeBuildInputs = [ pkgs.minica ];
+  } ''
+    minica -ca-cert ${ca_pem} -ca-key ${ca_key} \
+      -domains localhost
+    install -Dm444 -t $out localhost/{key,cert}.pem
   '';
-  key = runWithOpenSSL "matrix_key.pem" "openssl genrsa -out $out 2048";
-  csr = runWithOpenSSL "matrix.csr" ''
-    openssl req \
-       -new -key ${key} \
-       -out $out -subj "/CN=localhost" \
-  '';
-  cert = runWithOpenSSL "matrix_cert.pem" ''
-    openssl x509 \
-      -req -in ${csr} \
-      -CA ${ca_pem} -CAkey ${ca_key} \
-      -CAcreateserial -out $out \
-      -days 365
-  '';
-
 
   mailerCerts = import ../common/acme/server/snakeoil-certs.nix;
   mailerDomain = mailerCerts.domain;
@@ -82,8 +66,8 @@ in {
             host = "localhost";
             port = config.services.redis.servers.matrix-synapse.port;
           };
-          tls_certificate_path = "${cert}";
-          tls_private_key_path = "${key}";
+          tls_certificate_path = "${bundle}/cert.pem";
+          tls_private_key_path = "${bundle}/key.pem";
           registration_shared_secret = registrationSharedSecret;
           public_baseurl = "https://example.com";
           email = {
@@ -203,8 +187,8 @@ in {
         settings = {
           inherit listeners;
           database.name = "sqlite3";
-          tls_certificate_path = "${cert}";
-          tls_private_key_path = "${key}";
+          tls_certificate_path = "${bundle}/cert.pem";
+          tls_private_key_path = "${bundle}/key.pem";
         };
       };
     };
@@ -222,7 +206,7 @@ in {
         "journalctl -u matrix-synapse.service | grep -q 'Connected to redis'"
     )
     serverpostgres.require_unit_state("postgresql.service")
-    serverpostgres.succeed("register_new_matrix_user -u ${testUser} -p ${testPassword} -a -k ${registrationSharedSecret} https://localhost:8448/")
+    serverpostgres.succeed("REQUESTS_CA_BUNDLE=${ca_pem} register_new_matrix_user -u ${testUser} -p ${testPassword} -a -k ${registrationSharedSecret} https://localhost:8448/")
     serverpostgres.succeed("obtain-token-and-register-email")
     serversqlite.wait_for_unit("matrix-synapse.service")
     serversqlite.wait_until_succeeds(
diff --git a/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix b/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
index e638f2e5b861..addc898bd760 100644
--- a/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
+++ b/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
@@ -41,10 +41,13 @@ in {
         };
         secretFile = "/etc/nextcloud-secrets.json";
 
-        extraOptions.redis = {
-          dbindex = 0;
-          timeout = 1.5;
-          # password handled via secretfile below
+        extraOptions = {
+          allow_local_remote_servers = true;
+          redis = {
+            dbindex = 0;
+            timeout = 1.5;
+            # password handled via secretfile below
+          };
         };
         configureRedis = true;
       };
@@ -62,6 +65,7 @@ in {
 
       services.postgresql = {
         enable = true;
+        package = pkgs.postgresql_14;
       };
       systemd.services.postgresql.postStart = pkgs.lib.mkAfter ''
         password=$(cat ${passFile})
diff --git a/nixos/tests/nixops/default.nix b/nixos/tests/nixops/default.nix
index b8f747b2a19f..f7a26f2461c4 100644
--- a/nixos/tests/nixops/default.nix
+++ b/nixos/tests/nixops/default.nix
@@ -1,4 +1,6 @@
-{ pkgs, ... }:
+{ pkgs
+, testers
+, ... }:
 let
   inherit (pkgs) lib;
 
@@ -19,7 +21,7 @@ let
     passthru.override = args': testsForPackage (args // args');
   };
 
-  testLegacyNetwork = { nixopsPkg, ... }: pkgs.nixosTest ({
+  testLegacyNetwork = { nixopsPkg, ... }: testers.nixosTest ({
     name = "nixops-legacy-network";
     nodes = {
       deployer = { config, lib, nodes, pkgs, ... }: {
diff --git a/nixos/tests/systemd-initrd-luks-unl0kr.nix b/nixos/tests/systemd-initrd-luks-unl0kr.nix
new file mode 100644
index 000000000000..0658a098cfa2
--- /dev/null
+++ b/nixos/tests/systemd-initrd-luks-unl0kr.nix
@@ -0,0 +1,75 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: let
+  passphrase = "secret";
+in {
+  name = "systemd-initrd-luks-unl0kr";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ tomfitzhenry ];
+  };
+
+  enableOCR = true;
+
+  nodes.machine = { pkgs, ... }: {
+    virtualisation = {
+      emptyDiskImages = [ 512 512 ];
+      useBootLoader = true;
+      mountHostNixStore = true;
+      useEFIBoot = true;
+      qemu.options = [
+        "-vga virtio"
+      ];
+    };
+    boot.loader.systemd-boot.enable = true;
+
+    boot.initrd.availableKernelModules = [
+      "evdev" # for entering pw
+      "bochs"
+    ];
+
+    environment.systemPackages = with pkgs; [ cryptsetup ];
+    boot.initrd = {
+      systemd = {
+        enable = true;
+        emergencyAccess = true;
+      };
+      unl0kr.enable = true;
+    };
+
+    specialisation.boot-luks.configuration = {
+      boot.initrd.luks.devices = lib.mkVMOverride {
+        # We have two disks and only type one password - key reuse is in place
+        cryptroot.device = "/dev/vdb";
+        cryptroot2.device = "/dev/vdc";
+      };
+      virtualisation.rootDevice = "/dev/mapper/cryptroot";
+      virtualisation.fileSystems."/".autoFormat = true;
+      # test mounting device unlocked in initrd after switching root
+      virtualisation.fileSystems."/cryptroot2".device = "/dev/mapper/cryptroot2";
+    };
+  };
+
+  testScript = ''
+    # Create encrypted volume
+    machine.wait_for_unit("multi-user.target")
+    machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdb -")
+    machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdc -")
+    machine.succeed("echo -n ${passphrase} | cryptsetup luksOpen   -q               /dev/vdc cryptroot2")
+    machine.succeed("mkfs.ext4 /dev/mapper/cryptroot2")
+
+    # Boot from the encrypted disk
+    machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks.conf")
+    machine.succeed("sync")
+    machine.crash()
+
+    # Boot and decrypt the disk
+    machine.start()
+    machine.wait_for_text("Password required for booting")
+    machine.screenshot("prompt")
+    machine.send_chars("${passphrase}")
+    machine.screenshot("pw")
+    machine.send_chars("\n")
+    machine.wait_for_unit("multi-user.target")
+
+    assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount"), "/dev/mapper/cryptroot do not appear in mountpoints list"
+    assert "/dev/mapper/cryptroot2 on /cryptroot2 type ext4" in machine.succeed("mount")
+  '';
+})