diff options
Diffstat (limited to 'nixos/modules')
58 files changed, 1183 insertions, 418 deletions
diff --git a/nixos/modules/config/console.nix b/nixos/modules/config/console.nix index b60fc55851daf..97e6405db91e1 100644 --- a/nixos/modules/config/console.nix +++ b/nixos/modules/config/console.nix @@ -46,9 +46,9 @@ in type = with types; either str path; default = "Lat2-Terminus16"; example = "LatArCyrHeb-16"; - description = '' + description = mdDoc '' The font used for the virtual consoles. Leave empty to use - whatever the <command>setfont</command> program considers the + whatever the {command}`setfont` program considers the default font. Can be either a font name or a path to a PSF font file. ''; diff --git a/nixos/modules/config/debug-info.nix b/nixos/modules/config/debug-info.nix index 2942ae5905d10..78de26fda4403 100644 --- a/nixos/modules/config/debug-info.nix +++ b/nixos/modules/config/debug-info.nix @@ -9,21 +9,20 @@ with lib; environment.enableDebugInfo = mkOption { type = types.bool; default = false; - description = '' + description = mdDoc '' Some NixOS packages provide debug symbols. However, these are not included in the system closure by default to save disk space. Enabling this option causes the debug symbols to appear - in <filename>/run/current-system/sw/lib/debug/.build-id</filename>, - where tools such as <command>gdb</command> can find them. + in {file}`/run/current-system/sw/lib/debug/.build-id`, + where tools such as {command}`gdb` can find them. If you need debug symbols for a package that doesn't provide them by default, you can enable them as follows: - <programlisting> - nixpkgs.config.packageOverrides = pkgs: { - hello = pkgs.hello.overrideAttrs (oldAttrs: { - separateDebugInfo = true; - }); - }; - </programlisting> + + nixpkgs.config.packageOverrides = pkgs: { + hello = pkgs.hello.overrideAttrs (oldAttrs: { + separateDebugInfo = true; + }); + }; ''; }; diff --git a/nixos/modules/config/xdg/icons.nix b/nixos/modules/config/xdg/icons.nix index c83fdc251ef00..1e91670cf03bf 100644 --- a/nixos/modules/config/xdg/icons.nix +++ b/nixos/modules/config/xdg/icons.nix @@ -1,4 +1,4 @@ -{ config, lib, ... }: +{ config, lib, pkgs, ... }: with lib; { @@ -23,6 +23,12 @@ with lib; "/share/pixmaps" ]; + environment.systemPackages = [ + # Empty icon theme that contains index.theme file describing directories + # where toolkits should look for icons installed by apps. + pkgs.hicolor-icon-theme + ]; + # libXcursor looks for cursors in XCURSOR_PATH # it mostly follows the spec for icons # See: https://www.x.org/releases/current/doc/man/man3/Xcursor.3.xhtml Themes diff --git a/nixos/modules/hardware/device-tree.nix b/nixos/modules/hardware/device-tree.nix index be67116ad507d..5a8a8e27bee1b 100644 --- a/nixos/modules/hardware/device-tree.nix +++ b/nixos/modules/hardware/device-tree.nix @@ -36,14 +36,11 @@ let /plugin/; / { compatible = "raspberrypi"; - fragment@0 { - target-path = "/soc"; - __overlay__ { - pps { - compatible = "pps-gpio"; - status = "okay"; - }; - }; + }; + &{/soc} { + pps { + compatible = "pps-gpio"; + status = "okay"; }; }; ''; @@ -88,13 +85,14 @@ let # Compile single Device Tree overlay source # file (.dts) into its compiled variant (.dtbo) - compileDTS = name: f: pkgs.callPackage({ dtc }: pkgs.stdenv.mkDerivation { + compileDTS = name: f: pkgs.callPackage({ stdenv, dtc }: stdenv.mkDerivation { name = "${name}-dtbo"; nativeBuildInputs = [ dtc ]; buildCommand = '' - dtc -I dts ${f} -O dtb -@ -o $out + $CC -E -nostdinc -I${getDev cfg.kernelPackage}/lib/modules/${cfg.kernelPackage.modDirVersion}/source/scripts/dtc/include-prefixes -undef -D__DTS__ -x assembler-with-cpp ${f} | \ + dtc -I dts -O dtb -@ -o $out ''; }) {}; diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index a9b04bcc85959..b4717719661aa 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -183,6 +183,14 @@ in ''; example = literalExpression "config.boot.kernelPackages.nvidiaPackages.legacy_340"; }; + + hardware.nvidia.open = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to use the open source kernel module + ''; + }; }; config = let @@ -231,6 +239,11 @@ in ); message = "Required files for driver based power management don't exist."; } + + { + assertion = cfg.open -> (cfg.package ? open && cfg.package ? firmware); + message = "This version of NVIDIA driver does not provide a corresponding opensource kernel driver"; + } ]; # If Optimus/PRIME is enabled, we: @@ -364,7 +377,8 @@ in ++ optional (nvidia_x11.persistenced != null && config.virtualisation.docker.enableNvidia) "L+ /run/nvidia-docker/extras/bin/nvidia-persistenced - - - - ${nvidia_x11.persistenced}/origBin/nvidia-persistenced"; - boot.extraModulePackages = [ nvidia_x11.bin ]; + boot.extraModulePackages = if cfg.open then [ nvidia_x11.open ] else [ nvidia_x11.bin ]; + hardware.firmware = lib.optional cfg.open nvidia_x11.firmware; # nvidia-uvm is required by CUDA applications. boot.kernelModules = [ "nvidia-uvm" ] ++ @@ -372,7 +386,8 @@ in # If requested enable modesetting via kernel parameter. boot.kernelParams = optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1" - ++ optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1"; + ++ optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1" + ++ optional cfg.open "nvidia.NVreg_OpenRmEnableUnsupportedGpus=1"; services.udev.extraRules = '' diff --git a/nixos/modules/i18n/input-method/fcitx5.nix b/nixos/modules/i18n/input-method/fcitx5.nix index b4b887606e95e..9ef0285f7b933 100644 --- a/nixos/modules/i18n/input-method/fcitx5.nix +++ b/nixos/modules/i18n/input-method/fcitx5.nix @@ -32,6 +32,7 @@ in { GTK_IM_MODULE = "fcitx"; QT_IM_MODULE = "fcitx"; XMODIFIERS = "@im=fcitx"; + QT_PLUGIN_PATH = [ "${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}" ]; }; } (mkIf whetherRimeDataDir { diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-gnome.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-gnome.nix index 95aeca1a928a6..d015e10c11d81 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-gnome.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-gnome.nix @@ -18,7 +18,8 @@ extraGSettingsOverrides = '' [org.gnome.shell] welcome-dialog-last-shown-version='9999999999' - + [org.gnome.desktop.session] + idle-delay=0 [org.gnome.settings-daemon.plugins.power] sleep-inactive-ac-type='nothing' sleep-inactive-battery-type='nothing' diff --git a/nixos/modules/installer/kexec/kexec-boot.nix b/nixos/modules/installer/kexec/kexec-boot.nix deleted file mode 100644 index 2d062214efc21..0000000000000 --- a/nixos/modules/installer/kexec/kexec-boot.nix +++ /dev/null @@ -1,51 +0,0 @@ -# This module exposes a config.system.build.kexecBoot attribute, -# which returns a directory with kernel, initrd and a shell script -# running the necessary kexec commands. - -# It's meant to be scp'ed to a machine with working ssh and kexec binary -# installed. - -# This is useful for (cloud) providers where you can't boot a custom image, but -# get some Debian or Ubuntu installation. - -{ pkgs -, modulesPath -, config -, ... -}: -{ - imports = [ - (modulesPath + "/installer/netboot/netboot-minimal.nix") - ]; - - config = { - system.build.kexecBoot = - let - kexecScript = pkgs.writeScript "kexec-boot" '' - #!/usr/bin/env bash - if ! kexec -v >/dev/null 2>&1; then - echo "kexec not found: please install kexec-tools" 2>&1 - exit 1 - fi - SCRIPT_DIR=$( cd -- "$( dirname -- "''${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - kexec --load ''${SCRIPT_DIR}/bzImage \ - --initrd=''${SCRIPT_DIR}/initrd.gz \ - --command-line "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}" - kexec -e - ''; in - pkgs.linkFarm "kexec-tree" [ - { - name = "initrd.gz"; - path = "${config.system.build.netbootRamdisk}/initrd"; - } - { - name = "bzImage"; - path = "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}"; - } - { - name = "kexec-boot"; - path = kexecScript; - } - ]; - }; -} diff --git a/nixos/modules/installer/netboot/netboot.nix b/nixos/modules/installer/netboot/netboot.nix index a459e7304cd41..3127bdc436f92 100644 --- a/nixos/modules/installer/netboot/netboot.nix +++ b/nixos/modules/installer/netboot/netboot.nix @@ -101,6 +101,37 @@ with lib; boot ''; + # A script invoking kexec on ./bzImage and ./initrd.gz. + # Usually used through system.build.kexecTree, but exposed here for composability. + system.build.kexecScript = pkgs.writeScript "kexec-boot" '' + #!/usr/bin/env bash + if ! kexec -v >/dev/null 2>&1; then + echo "kexec not found: please install kexec-tools" 2>&1 + exit 1 + fi + SCRIPT_DIR=$( cd -- "$( dirname -- "''${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + kexec --load ''${SCRIPT_DIR}/bzImage \ + --initrd=''${SCRIPT_DIR}/initrd.gz \ + --command-line "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}" + kexec -e + ''; + + # A tree containing initrd.gz, bzImage and a kexec-boot script. + system.build.kexecTree = pkgs.linkFarm "kexec-tree" [ + { + name = "initrd.gz"; + path = "${config.system.build.netbootRamdisk}/initrd"; + } + { + name = "bzImage"; + path = "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}"; + } + { + name = "kexec-boot"; + path = config.system.build.kexecScript; + } + ]; + boot.loader.timeout = 10; boot.postBootCommands = diff --git a/nixos/modules/installer/sd-card/sd-image.nix b/nixos/modules/installer/sd-card/sd-image.nix index 7560c682517aa..c0335ea487592 100644 --- a/nixos/modules/installer/sd-card/sd-image.nix +++ b/nixos/modules/installer/sd-card/sd-image.nix @@ -18,7 +18,7 @@ with lib; let rootfsImage = pkgs.callPackage ../../../lib/make-ext4-fs.nix ({ inherit (config.sdImage) storePaths; - compressImage = true; + compressImage = config.sdImage.compressImage; populateImageCommands = config.sdImage.populateRootCommands; volumeLabel = "NIXOS_SD"; } // optionalAttrs (config.sdImage.rootPartitionUUID != null) { @@ -174,7 +174,8 @@ in mtools, libfaketime, util-linux, zstd }: stdenv.mkDerivation { name = config.sdImage.imageName; - nativeBuildInputs = [ dosfstools e2fsprogs mtools libfaketime util-linux zstd ]; + nativeBuildInputs = [ dosfstools e2fsprogs libfaketime mtools util-linux ] + ++ lib.optional config.sdImage.compressImage zstd; inherit (config.sdImage) imageName compressImage; @@ -189,14 +190,18 @@ in echo "file sd-image $img" >> $out/nix-support/hydra-build-products fi + root_fs=${rootfsImage} + ${lib.optionalString config.sdImage.compressImage '' + root_fs=./root-fs.img echo "Decompressing rootfs image" - zstd -d --no-progress "${rootfsImage}" -o ./root-fs.img + zstd -d --no-progress "${rootfsImage}" -o $root_fs + ''} # Gap in front of the first partition, in MiB gap=${toString config.sdImage.firmwarePartitionOffset} # Create the image file sized to fit /boot/firmware and /, plus slack for the gap. - rootSizeBlocks=$(du -B 512 --apparent-size ./root-fs.img | awk '{ print $1 }') + rootSizeBlocks=$(du -B 512 --apparent-size $root_fs | awk '{ print $1 }') firmwareSizeBlocks=$((${toString config.sdImage.firmwareSize} * 1024 * 1024 / 512)) imageSize=$((rootSizeBlocks * 512 + firmwareSizeBlocks * 512 + gap * 1024 * 1024)) truncate -s $imageSize $img @@ -214,7 +219,7 @@ in # Copy the rootfs into the SD image eval $(partx $img -o START,SECTORS --nr 2 --pairs) - dd conv=notrunc if=./root-fs.img of=$img seek=$START count=$SECTORS + dd conv=notrunc if=$root_fs of=$img seek=$START count=$SECTORS # Create a FAT32 /boot/firmware partition of suitable size into firmware_part.img eval $(partx $img -o START,SECTORS --nr 1 --pairs) diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index b74ec838df42f..1935d8252607c 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -84,6 +84,15 @@ sub debug { } +# nixpkgs.system +my ($status, @systemLines) = runCommand("nix-instantiate --impure --eval --expr builtins.currentSystem"); +if ($status != 0 || join("", @systemLines) =~ /error/) { + die "Failed to retrieve current system type from nix.\n"; +} +chomp(my $system = @systemLines[0]); +push @attrs, "nixpkgs.hostPlatform = lib.mkDefault $system;"; + + my $cpuinfo = read_file "/proc/cpuinfo"; diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix index 8e28d3336fa42..b031ff2f2be29 100644 --- a/nixos/modules/misc/documentation.nix +++ b/nixos/modules/misc/documentation.nix @@ -178,19 +178,12 @@ in man.generateCaches = mkOption { type = types.bool; default = false; - description = '' + description = mdDoc '' Whether to generate the manual page index caches. This allows searching for a page or - keyword using utilities like - <citerefentry> - <refentrytitle>apropos</refentrytitle> - <manvolnum>1</manvolnum> - </citerefentry> - and the <literal>-k</literal> option of - <citerefentry> - <refentrytitle>man</refentrytitle> - <manvolnum>1</manvolnum> - </citerefentry>. + keyword using utilities like {manpage}`apropos(1)` + and the `-k` option of + {manpage}`man(1)`. ''; }; @@ -216,16 +209,14 @@ in dev.enable = mkOption { type = types.bool; default = false; - description = '' + description = mdDoc '' Whether to install documentation targeted at developers. - <itemizedlist> - <listitem><para>This includes man pages targeted at developers if <option>documentation.man.enable</option> is - set (this also includes "devman" outputs).</para></listitem> - <listitem><para>This includes info pages targeted at developers if <option>documentation.info.enable</option> - is set (this also includes "devinfo" outputs).</para></listitem> - <listitem><para>This includes other pages targeted at developers if <option>documentation.doc.enable</option> - is set (this also includes "devdoc" outputs).</para></listitem> - </itemizedlist> + * This includes man pages targeted at developers if {option}`documentation.man.enable` is + set (this also includes "devman" outputs). + * This includes info pages targeted at developers if {option}`documentation.info.enable` + is set (this also includes "devinfo" outputs). + * This includes other pages targeted at developers if {option}`documentation.doc.enable` + is set (this also includes "devdoc" outputs). ''; }; diff --git a/nixos/modules/misc/man-db.nix b/nixos/modules/misc/man-db.nix index 8bd329bc4e0c3..7aeb02d883ac8 100644 --- a/nixos/modules/misc/man-db.nix +++ b/nixos/modules/misc/man-db.nix @@ -23,11 +23,11 @@ in ++ lib.optionals config.documentation.dev.enable [ "devman" ]; ignoreCollisions = true; }; - defaultText = lib.literalDocBook "all man pages in <option>config.environment.systemPackages</option>"; - description = '' - The manual pages to generate caches for if <option>documentation.man.generateCaches</option> + defaultText = lib.literalMD "all man pages in {option}`config.environment.systemPackages`"; + description = lib.mdDoc '' + The manual pages to generate caches for if {option}`documentation.man.generateCaches` is enabled. Must be a path to a directory with man pages under - <literal>/share/man</literal>; see the source for an example. + `/share/man`; see the source for an example. Advanced users can make this a content-addressed derivation to save a few rebuilds. ''; }; diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix index 866bb35160091..132a9b68ceb49 100644 --- a/nixos/modules/misc/nixpkgs.nix +++ b/nixos/modules/misc/nixpkgs.nix @@ -55,9 +55,46 @@ let check = builtins.isAttrs; }; - defaultPkgs = import ../../.. { - inherit (cfg) config overlays localSystem crossSystem; - }; + hasBuildPlatform = opt.buildPlatform.highestPrio < (mkOptionDefault {}).priority; + hasHostPlatform = opt.hostPlatform.isDefined; + hasPlatform = hasHostPlatform || hasBuildPlatform; + + # Context for messages + hostPlatformLine = optionalString hasHostPlatform "${showOptionWithDefLocs opt.hostPlatform}"; + buildPlatformLine = optionalString hasBuildPlatform "${showOptionWithDefLocs opt.buildPlatform}"; + platformLines = optionalString hasPlatform '' + Your system configuration configures nixpkgs with platform parameters: + ${hostPlatformLine + }${buildPlatformLine + }''; + + legacyOptionsDefined = + optional opt.system.isDefined opt.system + ++ (optional (opt.localSystem.highestPrio < (mkOptionDefault {}).priority) opt.localSystem) + ++ (optional (opt.crossSystem.highestPrio < (mkOptionDefault {}).priority) opt.crossSystem) + ; + + defaultPkgs = + if opt.hostPlatform.isDefined + then + let isCross = cfg.buildPlatform != cfg.hostPlatform; + systemArgs = + if isCross + then { + localSystem = cfg.buildPlatform; + crossSystem = cfg.hostPlatform; + } + else { + localSystem = cfg.hostPlatform; + }; + in + import ../../.. ({ + inherit (cfg) config overlays; + } // systemArgs) + else + import ../../.. { + inherit (cfg) config overlays localSystem crossSystem; + }; finalPkgs = if opt.pkgs.isDefined then cfg.pkgs.appendOverlays cfg.overlays else defaultPkgs; @@ -157,6 +194,46 @@ in ''; }; + hostPlatform = mkOption { + type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform + example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; }; + # Make sure that the final value has all fields for sake of other modules + # referring to this. TODO make `lib.systems` itself use the module system. + apply = lib.systems.elaborate; + defaultText = literalExpression + ''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform''; + description = '' + Specifies the platform where the NixOS configuration will run. + + To cross-compile, set also <code>nixpkgs.buildPlatform</code>. + + Ignored when <code>nixpkgs.pkgs</code> is set. + ''; + }; + + buildPlatform = mkOption { + type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform + default = cfg.hostPlatform; + example = { system = "x86_64-linux"; config = "x86_64-unknown-linux-gnu"; }; + # Make sure that the final value has all fields for sake of other modules + # referring to this. + apply = lib.systems.elaborate; + defaultText = literalExpression + ''config.nixpkgs.hostPlatform''; + description = '' + Specifies the platform on which NixOS should be built. + By default, NixOS is built on the system where it runs, but you can + change where it's built. Setting this option will cause NixOS to be + cross-compiled. + + For instance, if you're doing distributed multi-platform deployment, + or if you're building machines, you can set this to match your + development system and/or build farm. + + Ignored when <code>nixpkgs.pkgs</code> is set. + ''; + }; + localSystem = mkOption { type = types.attrs; # TODO utilize lib.systems.parsedPlatform default = { inherit (cfg) system; }; @@ -176,10 +253,13 @@ in deployment, or when building virtual machines. See its description in the Nixpkgs manual for more details. - Ignored when <code>nixpkgs.pkgs</code> is set. + Ignored when <code>nixpkgs.pkgs</code> or <code>hostPlatform</code> is set. ''; }; + # TODO deprecate. "crossSystem" is a nonsense identifier, because "cross" + # is a relation between at least 2 systems in the context of a + # specific build step, not a single system. crossSystem = mkOption { type = types.nullOr types.attrs; # TODO utilize lib.systems.parsedPlatform default = null; @@ -193,7 +273,7 @@ in should be set as null, the default. See its description in the Nixpkgs manual for more details. - Ignored when <code>nixpkgs.pkgs</code> is set. + Ignored when <code>nixpkgs.pkgs</code> or <code>hostPlatform</code> is set. ''; }; @@ -216,8 +296,7 @@ in </programlisting> See <code>nixpkgs.localSystem</code> for more information. - Ignored when <code>nixpkgs.localSystem</code> is set. - Ignored when <code>nixpkgs.pkgs</code> is set. + Ignored when <code>nixpkgs.pkgs</code>, <code>nixpkgs.localSystem</code> or <code>nixpkgs.hostPlatform</code> is set. ''; }; }; @@ -240,10 +319,23 @@ in else "nixpkgs.localSystem"; pkgsSystem = finalPkgs.stdenv.targetPlatform.system; in { - assertion = nixosExpectedSystem == pkgsSystem; + assertion = !hasPlatform -> nixosExpectedSystem == pkgsSystem; message = "The NixOS nixpkgs.pkgs option was set to a Nixpkgs invocation that compiles to target system ${pkgsSystem} but NixOS was configured for system ${nixosExpectedSystem} via NixOS option ${nixosOption}. The NixOS system settings must match the Nixpkgs target system."; } ) + { + assertion = hasPlatform -> legacyOptionsDefined == []; + message = '' + Your system configures nixpkgs with the platform parameter${optionalString hasBuildPlatform "s"}: + ${hostPlatformLine + }${buildPlatformLine + } + However, it also defines the legacy options: + ${concatMapStrings showOptionWithDefLocs legacyOptionsDefined} + For a future proof system configuration, we recommend to remove + the legacy definitions. + ''; + } ]; }; diff --git a/nixos/modules/misc/nixpkgs/test.nix b/nixos/modules/misc/nixpkgs/test.nix index ec5fab9fb4a5e..9e8851707f8fc 100644 --- a/nixos/modules/misc/nixpkgs/test.nix +++ b/nixos/modules/misc/nixpkgs/test.nix @@ -1,8 +1,63 @@ { evalMinimalConfig, pkgs, lib, stdenv }: +let + eval = mod: evalMinimalConfig { + imports = [ ../nixpkgs.nix mod ]; + }; + withHost = eval { + nixpkgs.hostPlatform = "aarch64-linux"; + }; + withHostAndBuild = eval { + nixpkgs.hostPlatform = "aarch64-linux"; + nixpkgs.buildPlatform = "aarch64-darwin"; + }; + ambiguous = { + _file = "ambiguous.nix"; + nixpkgs.hostPlatform = "aarch64-linux"; + nixpkgs.buildPlatform = "aarch64-darwin"; + nixpkgs.system = "x86_64-linux"; + nixpkgs.localSystem.system = "x86_64-darwin"; + nixpkgs.crossSystem.system = "i686-linux"; + imports = [ + { _file = "repeat.nix"; + nixpkgs.hostPlatform = "aarch64-linux"; + } + ]; + }; + getErrors = module: + let + uncheckedEval = lib.evalModules { modules = [ ../nixpkgs.nix module ]; }; + in map (ass: ass.message) (lib.filter (ass: !ass.assertion) uncheckedEval.config.assertions); +in lib.recurseIntoAttrs { invokeNixpkgsSimple = - (evalMinimalConfig ({ config, modulesPath, ... }: { - imports = [ (modulesPath + "/misc/nixpkgs.nix") ]; + (eval { nixpkgs.system = stdenv.hostPlatform.system; - }))._module.args.pkgs.hello; + })._module.args.pkgs.hello; + assertions = + assert withHost._module.args.pkgs.stdenv.hostPlatform.system == "aarch64-linux"; + assert withHost._module.args.pkgs.stdenv.buildPlatform.system == "aarch64-linux"; + assert withHostAndBuild._module.args.pkgs.stdenv.hostPlatform.system == "aarch64-linux"; + assert withHostAndBuild._module.args.pkgs.stdenv.buildPlatform.system == "aarch64-darwin"; + assert builtins.trace (lib.head (getErrors ambiguous)) + getErrors ambiguous == + ['' + Your system configures nixpkgs with the platform parameters: + nixpkgs.hostPlatform, with values defined in: + - repeat.nix + - ambiguous.nix + nixpkgs.buildPlatform, with values defined in: + - ambiguous.nix + + However, it also defines the legacy options: + nixpkgs.system, with values defined in: + - ambiguous.nix + nixpkgs.localSystem, with values defined in: + - ambiguous.nix + nixpkgs.crossSystem, with values defined in: + - ambiguous.nix + + For a future proof system configuration, we recommend to remove + the legacy definitions. + '']; + pkgs.emptyFile; } diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 495be43ec5614..b0fd06e66e02f 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -141,7 +141,6 @@ ./programs/cdemu.nix ./programs/cfs-zen-tweaks.nix ./programs/chromium.nix - ./programs/clickshare.nix ./programs/cnping.nix ./programs/command-not-found/command-not-found.nix ./programs/criu.nix @@ -169,6 +168,7 @@ ./programs/gpaste.nix ./programs/gnupg.nix ./programs/gphoto2.nix + ./programs/haguichi.nix ./programs/hamster.nix ./programs/htop.nix ./programs/iftop.nix @@ -196,6 +196,7 @@ ./programs/npm.nix ./programs/noisetorch.nix ./programs/oblogout.nix + ./programs/openvpn3.nix ./programs/pantheon-tweaks.nix ./programs/partition-manager.nix ./programs/plotinus.nix @@ -514,6 +515,7 @@ ./services/mail/rspamd.nix ./services/mail/rss2email.nix ./services/mail/roundcube.nix + ./services/mail/schleuder.nix ./services/mail/sympa.nix ./services/mail/nullmailer.nix ./services/matrix/appservice-discord.nix @@ -658,6 +660,7 @@ ./services/monitoring/do-agent.nix ./services/monitoring/fusion-inventory.nix ./services/monitoring/grafana.nix + ./services/monitoring/grafana-agent.nix ./services/monitoring/grafana-image-renderer.nix ./services/monitoring/grafana-reporter.nix ./services/monitoring/graphite.nix @@ -771,6 +774,7 @@ ./services/networking/ergo.nix ./services/networking/ergochat.nix ./services/networking/eternal-terminal.nix + ./services/networking/expressvpn.nix ./services/networking/fakeroute.nix ./services/networking/ferm.nix ./services/networking/fireqos.nix @@ -890,6 +894,7 @@ ./services/networking/redsocks.nix ./services/networking/resilio.nix ./services/networking/robustirc-bridge.nix + ./services/networking/routedns.nix ./services/networking/rpcbind.nix ./services/networking/rxe.nix ./services/networking/sabnzbd.nix diff --git a/nixos/modules/programs/clickshare.nix b/nixos/modules/programs/clickshare.nix deleted file mode 100644 index 9980a7daf5254..0000000000000 --- a/nixos/modules/programs/clickshare.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - - options.programs.clickshare-csc1.enable = - lib.options.mkEnableOption '' - Barco ClickShare CSC-1 driver/client. - This allows users in the <literal>clickshare</literal> - group to access and use a ClickShare USB dongle - that is connected to the machine - ''; - - config = lib.modules.mkIf config.programs.clickshare-csc1.enable { - environment.systemPackages = [ pkgs.clickshare-csc1 ]; - services.udev.packages = [ pkgs.clickshare-csc1 ]; - users.groups.clickshare = {}; - }; - - meta.maintainers = [ lib.maintainers.yarny ]; - -} diff --git a/nixos/modules/programs/haguichi.nix b/nixos/modules/programs/haguichi.nix new file mode 100644 index 0000000000000..4f48551cf1dac --- /dev/null +++ b/nixos/modules/programs/haguichi.nix @@ -0,0 +1,15 @@ +{ lib, pkgs, config, ... }: + +with lib; + +{ + options.programs.haguichi = { + enable = mkEnableOption "Haguichi, a Linux GUI frontend to the proprietary LogMeIn Hamachi"; + }; + + config = mkIf config.programs.haguichi.enable { + environment.systemPackages = with pkgs; [ haguichi ]; + + services.logmein-hamachi.enable = true; + }; +} diff --git a/nixos/modules/programs/openvpn3.nix b/nixos/modules/programs/openvpn3.nix new file mode 100644 index 0000000000000..f3101d3cebdc9 --- /dev/null +++ b/nixos/modules/programs/openvpn3.nix @@ -0,0 +1,33 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.openvpn3; +in +{ + options.programs.openvpn3 = { + enable = mkEnableOption "the openvpn3 client"; + }; + + config = mkIf cfg.enable { + services.dbus.packages = with pkgs; [ + openvpn3 + ]; + + users.users.openvpn = { + isSystemUser = true; + uid = config.ids.uids.openvpn; + group = "openvpn"; + }; + + users.groups.openvpn = { + gid = config.ids.gids.openvpn; + }; + + environment.systemPackages = with pkgs; [ + openvpn3 + ]; + }; + +} diff --git a/nixos/modules/security/systemd-confinement.nix b/nixos/modules/security/systemd-confinement.nix index f3a2de3bf87a0..07b725effb7d1 100644 --- a/nixos/modules/security/systemd-confinement.nix +++ b/nixos/modules/security/systemd-confinement.nix @@ -22,16 +22,17 @@ in { options.confinement.fullUnit = lib.mkOption { type = types.bool; default = false; - description = '' + description = lib.mdDoc '' Whether to include the full closure of the systemd unit file into the chroot, instead of just the dependencies for the executables. - <warning><para>While it may be tempting to just enable this option to + ::: {.warning} + While it may be tempting to just enable this option to make things work quickly, please be aware that this might add paths to the closure of the chroot that you didn't anticipate. It's better - to use <option>confinement.packages</option> to <emphasis - role="strong">explicitly</emphasis> add additional store paths to the - chroot.</para></warning> + to use {option}`confinement.packages` to **explicitly** add additional store paths to the + chroot. + ::: ''; }; diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix index 586b9ffa68888..11733d99fca65 100644 --- a/nixos/modules/services/audio/mpd.nix +++ b/nixos/modules/services/audio/mpd.nix @@ -215,6 +215,7 @@ in { systemd.sockets.mpd = mkIf cfg.startWhenNeeded { wantedBy = [ "sockets.target" ]; listenStreams = [ + "" # Note: this is needed to override the upstream unit (if pkgs.lib.hasPrefix "/" cfg.network.listenAddress then cfg.network.listenAddress else "${optionalString (cfg.network.listenAddress != "any") "${cfg.network.listenAddress}:"}${toString cfg.network.port}") diff --git a/nixos/modules/services/audio/navidrome.nix b/nixos/modules/services/audio/navidrome.nix index 3660e05310be1..b50cb04155697 100644 --- a/nixos/modules/services/audio/navidrome.nix +++ b/nixos/modules/services/audio/navidrome.nix @@ -45,6 +45,8 @@ in { RootDirectory = "/run/navidrome"; ReadWritePaths = ""; BindReadOnlyPaths = [ + # navidrome uses online services to download additional album metadata / covers + "${config.environment.etc."ssl/certs/ca-certificates.crt".source}:/etc/ssl/certs/ca-certificates.crt" builtins.storeDir ] ++ lib.optional (cfg.settings ? MusicFolder) cfg.settings.MusicFolder; CapabilityBoundingSet = ""; diff --git a/nixos/modules/services/cluster/k3s/default.nix b/nixos/modules/services/cluster/k3s/default.nix index 3a36cfa3f37b8..421aa0aac60ed 100644 --- a/nixos/modules/services/cluster/k3s/default.nix +++ b/nixos/modules/services/cluster/k3s/default.nix @@ -3,8 +3,14 @@ with lib; let cfg = config.services.k3s; + removeOption = config: instruction: + lib.mkRemovedOptionModule ([ "services" "k3s" ] ++ config) instruction; in { + imports = [ + (removeOption [ "docker" ] "k3s docker option is no longer supported.") + ]; + # interface options.services.k3s = { enable = mkEnableOption "k3s"; @@ -48,12 +54,6 @@ in default = null; }; - docker = mkOption { - type = types.bool; - default = false; - description = "Use docker to run containers rather than the built-in containerd."; - }; - extraFlags = mkOption { description = "Extra flags to pass to the k3s command."; type = types.str; @@ -88,14 +88,11 @@ in } ]; - virtualisation.docker = mkIf cfg.docker { - enable = mkDefault true; - }; environment.systemPackages = [ config.services.k3s.package ]; systemd.services.k3s = { description = "k3s service"; - after = [ "network.service" "firewall.service" ] ++ (optional cfg.docker "docker.service"); + after = [ "network.service" "firewall.service" ]; wants = [ "network.service" "firewall.service" ]; wantedBy = [ "multi-user.target" ]; path = optional config.boot.zfs.enabled config.boot.zfs.package; @@ -113,8 +110,8 @@ in ExecStart = concatStringsSep " \\\n " ( [ "${cfg.package}/bin/k3s ${cfg.role}" - ] ++ (optional cfg.docker "--docker") - ++ (optional (cfg.docker && config.systemd.enableUnifiedCgroupHierarchy) "--kubelet-arg=cgroup-driver=systemd") + ] + ++ (optional (config.systemd.enableUnifiedCgroupHierarchy) "--kubelet-arg=cgroup-driver=systemd") ++ (optional cfg.disableAgent "--disable-agent") ++ (optional (cfg.serverAddr != "") "--server ${cfg.serverAddr}") ++ (optional (cfg.token != "") "--token ${cfg.token}") diff --git a/nixos/modules/services/databases/cassandra.nix b/nixos/modules/services/databases/cassandra.nix index b36cac35e7c29..b457e69babaad 100644 --- a/nixos/modules/services/databases/cassandra.nix +++ b/nixos/modules/services/databases/cassandra.nix @@ -4,11 +4,12 @@ let inherit (lib) concatStringsSep flip - literalDocBook + literalMD literalExpression optionalAttrs optionals recursiveUpdate + mdDoc mkEnableOption mkIf mkOption @@ -107,7 +108,7 @@ in clusterName = mkOption { type = types.str; default = "Test Cluster"; - description = '' + description = mdDoc '' The name of the cluster. This setting prevents nodes in one logical cluster from joining another. All nodes in a cluster must have the same value. @@ -117,19 +118,19 @@ in user = mkOption { type = types.str; default = defaultUser; - description = "Run Apache Cassandra under this user."; + description = mdDoc "Run Apache Cassandra under this user."; }; group = mkOption { type = types.str; default = defaultUser; - description = "Run Apache Cassandra under this group."; + description = mdDoc "Run Apache Cassandra under this group."; }; homeDir = mkOption { type = types.path; default = "/var/lib/cassandra"; - description = '' + description = mdDoc '' Home directory for Apache Cassandra. ''; }; @@ -139,7 +140,7 @@ in default = pkgs.cassandra; defaultText = literalExpression "pkgs.cassandra"; example = literalExpression "pkgs.cassandra_3_11"; - description = '' + description = mdDoc '' The Apache Cassandra package to use. ''; }; @@ -147,8 +148,8 @@ in jvmOpts = mkOption { type = types.listOf types.str; default = [ ]; - description = '' - Populate the JVM_OPT environment variable. + description = mdDoc '' + Populate the `JVM_OPT` environment variable. ''; }; @@ -156,20 +157,20 @@ in type = types.nullOr types.str; default = "127.0.0.1"; example = null; - description = '' + description = mdDoc '' Address or interface to bind to and tell other Cassandra nodes to connect to. You _must_ change this if you want multiple nodes to be able to communicate! - Set listenAddress OR listenInterface, not both. + Set {option}`listenAddress` OR {option}`listenInterface`, not both. Leaving it blank leaves it up to - InetAddress.getLocalHost(). This will always do the Right - Thing _if_ the node is properly configured (hostname, name + `InetAddress.getLocalHost()`. This will always do the "Right + Thing" _if_ the node is properly configured (hostname, name resolution, etc), and the Right Thing is to use the address associated with the hostname (it might not be). - Setting listen_address to 0.0.0.0 is always wrong. + Setting {option}`listenAddress` to `0.0.0.0` is always wrong. ''; }; @@ -177,8 +178,8 @@ in type = types.nullOr types.str; default = null; example = "eth1"; - description = '' - Set listenAddress OR listenInterface, not both. Interfaces + description = mdDoc '' + Set `listenAddress` OR `listenInterface`, not both. Interfaces must correspond to a single address, IP aliasing is not supported. ''; @@ -188,18 +189,18 @@ in type = types.nullOr types.str; default = "127.0.0.1"; example = null; - description = '' + description = mdDoc '' The address or interface to bind the native transport server to. - Set rpcAddress OR rpcInterface, not both. + Set {option}`rpcAddress` OR {option}`rpcInterface`, not both. - Leaving rpcAddress blank has the same effect as on - listenAddress (i.e. it will be based on the configured hostname + Leaving {option}`rpcAddress` blank has the same effect as on + {option}`listenAddress` (i.e. it will be based on the configured hostname of the node). - Note that unlike listenAddress, you can specify 0.0.0.0, but you - must also set extraConfig.broadcast_rpc_address to a value other - than 0.0.0.0. + Note that unlike {option}`listenAddress`, you can specify `"0.0.0.0"`, but you + must also set `extraConfig.broadcast_rpc_address` to a value other + than `"0.0.0.0"`. For security reasons, you should not expose this port to the internet. Firewall it if needed. @@ -210,8 +211,8 @@ in type = types.nullOr types.str; default = null; example = "eth1"; - description = '' - Set rpcAddress OR rpcInterface, not both. Interfaces must + description = mdDoc '' + Set {option}`rpcAddress` OR {option}`rpcInterface`, not both. Interfaces must correspond to a single address, IP aliasing is not supported. ''; }; @@ -233,7 +234,7 @@ in <logger name="com.thinkaurelius.thrift" level="ERROR"/> </configuration> ''; - description = '' + description = mdDoc '' XML logback configuration for cassandra ''; }; @@ -241,24 +242,24 @@ in seedAddresses = mkOption { type = types.listOf types.str; default = [ "127.0.0.1" ]; - description = '' + description = mdDoc '' The addresses of hosts designated as contact points in the cluster. A joining node contacts one of the nodes in the seeds list to learn the topology of the ring. - Set to 127.0.0.1 for a single node cluster. + Set to `[ "127.0.0.1" ]` for a single node cluster. ''; }; allowClients = mkOption { type = types.bool; default = true; - description = '' + description = mdDoc '' Enables or disables the native transport server (CQL binary protocol). - This server uses the same address as the <literal>rpcAddress</literal>, - but the port it uses is not <literal>rpc_port</literal> but - <literal>native_transport_port</literal>. See the official Cassandra + This server uses the same address as the {option}`rpcAddress`, + but the port it uses is not `rpc_port` but + `native_transport_port`. See the official Cassandra docs for more information on these variables and set them using - <literal>extraConfig</literal>. + {option}`extraConfig`. ''; }; @@ -269,8 +270,8 @@ in { commitlog_sync_batch_window_in_ms = 3; }; - description = '' - Extra options to be merged into cassandra.yaml as nix attribute set. + description = mdDoc '' + Extra options to be merged into {file}`cassandra.yaml` as nix attribute set. ''; }; @@ -278,8 +279,8 @@ in type = types.lines; default = ""; example = literalExpression ''"CLASSPATH=$CLASSPATH:''${extraJar}"''; - description = '' - Extra shell lines to be appended onto cassandra-env.sh. + description = mdDoc '' + Extra shell lines to be appended onto {file}`cassandra-env.sh`. ''; }; @@ -287,13 +288,13 @@ in type = types.nullOr types.str; default = "3w"; example = null; - description = '' + description = mdDoc '' Set the interval how often full repairs are run, i.e. - <literal>nodetool repair --full</literal> is executed. See - https://cassandra.apache.org/doc/latest/operating/repair.html + {command}`nodetool repair --full` is executed. See + <https://cassandra.apache.org/doc/latest/operating/repair.html> for more information. - Set to <literal>null</literal> to disable full repairs. + Set to `null` to disable full repairs. ''; }; @@ -301,7 +302,7 @@ in type = types.listOf types.str; default = [ ]; example = [ "--partitioner-range" ]; - description = '' + description = mdDoc '' Options passed through to the full repair command. ''; }; @@ -310,13 +311,13 @@ in type = types.nullOr types.str; default = "3d"; example = null; - description = '' + description = mdDoc '' Set the interval how often incremental repairs are run, i.e. - <literal>nodetool repair</literal> is executed. See - https://cassandra.apache.org/doc/latest/operating/repair.html + {command}`nodetool repair` is executed. See + <https://cassandra.apache.org/doc/latest/operating/repair.html> for more information. - Set to <literal>null</literal> to disable incremental repairs. + Set to `null` to disable incremental repairs. ''; }; @@ -324,7 +325,7 @@ in type = types.listOf types.str; default = [ ]; example = [ "--partitioner-range" ]; - description = '' + description = mdDoc '' Options passed through to the incremental repair command. ''; }; @@ -333,15 +334,15 @@ in type = types.nullOr types.str; default = null; example = "4G"; - description = '' - Must be left blank or set together with heapNewSize. + description = mdDoc '' + Must be left blank or set together with {option}`heapNewSize`. If left blank a sensible value for the available amount of RAM and CPU cores is calculated. Override to set the amount of memory to allocate to the JVM at start-up. For production use you may wish to adjust this for your - environment. MAX_HEAP_SIZE is the total amount of memory dedicated - to the Java heap. HEAP_NEWSIZE refers to the size of the young + environment. `MAX_HEAP_SIZE` is the total amount of memory dedicated + to the Java heap. `HEAP_NEWSIZE` refers to the size of the young generation. The main trade-off for the young generation is that the larger it @@ -354,21 +355,21 @@ in type = types.nullOr types.str; default = null; example = "800M"; - description = '' - Must be left blank or set together with heapNewSize. + description = mdDoc '' + Must be left blank or set together with {option}`heapNewSize`. If left blank a sensible value for the available amount of RAM and CPU cores is calculated. Override to set the amount of memory to allocate to the JVM at start-up. For production use you may wish to adjust this for your - environment. HEAP_NEWSIZE refers to the size of the young + environment. `HEAP_NEWSIZE` refers to the size of the young generation. The main trade-off for the young generation is that the larger it is, the longer GC pause times will be. The shorter it is, the more expensive GC will be (usually). - The example HEAP_NEWSIZE assumes a modern 8-core+ machine for decent pause + The example `HEAP_NEWSIZE` assumes a modern 8-core+ machine for decent pause times. If in doubt, and if you do not particularly want to tweak, go with 100 MB per physical CPU core. ''; @@ -378,7 +379,7 @@ in type = types.nullOr types.int; default = null; example = 4; - description = '' + description = mdDoc '' Set this to control the amount of arenas per-thread in glibc. ''; }; @@ -386,19 +387,19 @@ in remoteJmx = mkOption { type = types.bool; default = false; - description = '' + description = mdDoc '' Cassandra ships with JMX accessible *only* from localhost. To enable remote JMX connections set to true. Be sure to also enable authentication and/or TLS. - See: https://wiki.apache.org/cassandra/JmxSecurity + See: <https://wiki.apache.org/cassandra/JmxSecurity> ''; }; jmxPort = mkOption { type = types.int; default = 7199; - description = '' + description = mdDoc '' Specifies the default port over which Cassandra will be available for JMX connections. For security reasons, you should not expose this port to the internet. @@ -408,11 +409,11 @@ in jmxRoles = mkOption { default = [ ]; - description = '' - Roles that are allowed to access the JMX (e.g. nodetool) - BEWARE: The passwords will be stored world readable in the nix-store. + description = mdDoc '' + Roles that are allowed to access the JMX (e.g. {command}`nodetool`) + BEWARE: The passwords will be stored world readable in the nix store. It's recommended to use your own protected file using - <literal>jmxRolesFile</literal> + {option}`jmxRolesFile` Doesn't work in versions older than 3.11 because they don't like that it's world readable. @@ -437,7 +438,7 @@ in if versionAtLeast cfg.package.version "3.11" then pkgs.writeText "jmx-roles-file" defaultJmxRolesFile else null; - defaultText = literalDocBook ''generated configuration file if version is at least 3.11, otherwise <literal>null</literal>''; + defaultText = literalMD ''generated configuration file if version is at least 3.11, otherwise `null`''; example = "/var/lib/cassandra/jmx.password"; description = '' Specify your own jmx roles file. diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix index 1967a2371bdd7..d80d1b07b97c3 100644 --- a/nixos/modules/services/databases/openldap.nix +++ b/nixos/modules/services/databases/openldap.nix @@ -312,6 +312,7 @@ in { "-h" (lib.concatStringsSep " " cfg.urlList) ]); Type = "notify"; + NotifyAccess = "all"; PIDFile = cfg.settings.attrs.olcPidFile; }; }; diff --git a/nixos/modules/services/desktops/pipewire/pipewire.nix b/nixos/modules/services/desktops/pipewire/pipewire.nix index 07b5dd12ffc54..dd1f5e3a018db 100644 --- a/nixos/modules/services/desktops/pipewire/pipewire.nix +++ b/nixos/modules/services/desktops/pipewire/pipewire.nix @@ -234,7 +234,7 @@ in { environment.etc."pipewire/pipewire.conf" = { source = json.generate "pipewire.conf" configs.pipewire; }; - environment.etc."pipewire/pipewire-pulse.conf" = { + environment.etc."pipewire/pipewire-pulse.conf" = mkIf cfg.pulse.enable { source = json.generate "pipewire-pulse.conf" configs.pipewire-pulse; }; @@ -260,5 +260,8 @@ in { # https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/464#note_723554 systemd.services.pipewire.environment."PIPEWIRE_LINK_PASSIVE" = "1"; systemd.user.services.pipewire.environment."PIPEWIRE_LINK_PASSIVE" = "1"; + + # pipewire-pulse default config expects pactl to be in PATH + systemd.user.services.pipewire-pulse.path = lib.mkIf cfg.pulse.enable [ pkgs.pulseaudio ]; }; } diff --git a/nixos/modules/services/desktops/pipewire/wireplumber.nix b/nixos/modules/services/desktops/pipewire/wireplumber.nix index 1dbdd842c4a1e..439a3ae68daa1 100644 --- a/nixos/modules/services/desktops/pipewire/wireplumber.nix +++ b/nixos/modules/services/desktops/pipewire/wireplumber.nix @@ -37,11 +37,19 @@ in environment.systemPackages = [ cfg.package ]; environment.etc."wireplumber/main.lua.d/80-nixos.lua" = lib.mkIf (!pwUsedForAudio) { - text = '' + text = '' -- Pipewire is not used for audio, so prevent it from grabbing audio devices alsa_monitor.enable = function() end ''; }; + environment.etc."wireplumber/main.lua.d/80-systemwide.lua" = lib.mkIf config.services.pipewire.systemWide { + text = '' + -- When running system-wide, these settings need to be disabled (they + -- use functions that aren't available on the system dbus). + alsa_monitor.properties["alsa.reserve"] = false + default_access.properties["enable-flatpak-portal"] = false + ''; + }; systemd.packages = [ cfg.package ]; @@ -50,5 +58,10 @@ in systemd.services.wireplumber.wantedBy = [ "pipewire.service" ]; systemd.user.services.wireplumber.wantedBy = [ "pipewire.service" ]; + + systemd.services.wireplumber.environment = lib.mkIf config.services.pipewire.systemWide { + # Force wireplumber to use system dbus. + DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/dbus/system_bus_socket"; + }; }; } diff --git a/nixos/modules/services/home-automation/home-assistant.nix b/nixos/modules/services/home-automation/home-assistant.nix index e255e5d22188b..2aacc5e55c6e2 100644 --- a/nixos/modules/services/home-automation/home-assistant.nix +++ b/nixos/modules/services/home-automation/home-assistant.nix @@ -369,6 +369,17 @@ in { networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.config.http.server_port ]; + # symlink the configuration to /etc/home-assistant + environment.etc = lib.mkMerge [ + (lib.mkIf (cfg.config != null && !cfg.configWritable) { + "home-assistant/configuration.yaml".source = configFile; + }) + + (lib.mkIf (cfg.lovelaceConfig != null && !cfg.lovelaceConfigWritable) { + "home-assistant/ui-lovelace.yaml".source = lovelaceConfigFile; + }) + ]; + systemd.services.home-assistant = { description = "Home Assistant"; after = [ @@ -378,18 +389,22 @@ in { "mysql.service" "postgresql.service" ]; + reloadTriggers = [ + configFile + lovelaceConfigFile + ]; preStart = let copyConfig = if cfg.configWritable then '' cp --no-preserve=mode ${configFile} "${cfg.configDir}/configuration.yaml" '' else '' rm -f "${cfg.configDir}/configuration.yaml" - ln -s ${configFile} "${cfg.configDir}/configuration.yaml" + ln -s /etc/home-assistant/configuration.yaml "${cfg.configDir}/configuration.yaml" ''; copyLovelaceConfig = if cfg.lovelaceConfigWritable then '' cp --no-preserve=mode ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml" '' else '' rm -f "${cfg.configDir}/ui-lovelace.yaml" - ln -s ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml" + ln -s /etc/home-assistant/ui-lovelace.yaml "${cfg.configDir}/ui-lovelace.yaml" ''; in (optionalString (cfg.config != null) copyConfig) + diff --git a/nixos/modules/services/mail/schleuder.nix b/nixos/modules/services/mail/schleuder.nix new file mode 100644 index 0000000000000..7ba15f1070bde --- /dev/null +++ b/nixos/modules/services/mail/schleuder.nix @@ -0,0 +1,162 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.services.schleuder; + settingsFormat = pkgs.formats.yaml { }; + postfixMap = entries: lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "${name} ${value}") entries); + writePostfixMap = name: entries: pkgs.writeText name (postfixMap entries); + configScript = pkgs.writeScript "schleuder-cfg" '' + #!${pkgs.runtimeShell} + set -exuo pipefail + umask 0077 + ${pkgs.yq}/bin/yq \ + --slurpfile overrides <(${pkgs.yq}/bin/yq . <${lib.escapeShellArg cfg.extraSettingsFile}) \ + < ${settingsFormat.generate "schleuder.yml" cfg.settings} \ + '. * $overrides[0]' \ + > /etc/schleuder/schleuder.yml + chown schleuder: /etc/schleuder/schleuder.yml + ''; +in +{ + options.services.schleuder = { + enable = lib.mkEnableOption "Schleuder secure remailer"; + enablePostfix = lib.mkEnableOption "automatic postfix integration" // { default = true; }; + lists = lib.mkOption { + description = '' + List of list addresses that should be handled by Schleuder. + + Note that this is only handled by the postfix integration, and + the setup of the lists, their members and their keys has to be + performed separately via schleuder's API, using a tool such as + schleuder-cli. + ''; + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ "widget-team@example.com" "security@example.com" ]; + }; + /* maybe one day.... + domains = lib.mkOption { + description = "Domains for which all mail should be handled by Schleuder."; + type = lib.types.listOf lib.types.str; + default = []; + example = ["securelists.example.com"]; + }; + */ + settings = lib.mkOption { + description = '' + Settings for schleuder.yml. + + Check the <link xlink:href="https://0xacab.org/schleuder/schleuder/blob/master/etc/schleuder.yml">example configuration</link> for possible values. + ''; + type = lib.types.submodule { + freeformType = settingsFormat.type; + options.keyserver = lib.mkOption { + type = lib.types.str; + description = '' + Key server from which to fetch and update keys. + + Note that NixOS uses a different default from upstream, since the upstream default sks-keyservers.net is deprecated. + ''; + default = "keys.openpgp.org"; + }; + }; + default = { }; + }; + extraSettingsFile = lib.mkOption { + description = "YAML file to merge into the schleuder config at runtime. This can be used for secrets such as API keys."; + type = lib.types.nullOr lib.types.path; + default = null; + }; + listDefaults = lib.mkOption { + description = '' + Default settings for lists (list-defaults.yml). + + Check the <link xlink:href="https://0xacab.org/schleuder/schleuder/-/blob/master/etc/list-defaults.yml">example configuration</link> for possible values. + ''; + type = settingsFormat.type; + default = { }; + }; + }; + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = !(cfg.settings.api ? valid_api_keys); + message = '' + services.schleuder.settings.api.valid_api_keys is set. Defining API keys via NixOS config results in them being copied to the world-readable Nix store. Please use the extraSettingsFile option to store API keys in a non-public location. + ''; + } + { + assertion = !(lib.any (db: db ? password) (lib.attrValues cfg.settings.database or {})); + message = '' + A password is defined for at least one database in services.schleuder.settings.database. Defining passwords via NixOS config results in them being copied to the world-readable Nix store. Please use the extraSettingsFile option to store database passwords in a non-public location. + ''; + } + ]; + users.users.schleuder.isSystemUser = true; + users.users.schleuder.group = "schleuder"; + users.groups.schleuder = {}; + environment.systemPackages = [ + pkgs.schleuder-cli + ]; + services.postfix = lib.mkIf cfg.enablePostfix { + extraMasterConf = '' + schleuder unix - n n - - pipe + flags=DRhu user=schleuder argv=/${pkgs.schleuder}/bin/schleuder work ''${recipient} + ''; + transport = lib.mkIf (cfg.lists != [ ]) (postfixMap (lib.genAttrs cfg.lists (_: "schleuder:"))); + extraConfig = '' + schleuder_destination_recipient_limit = 1 + ''; + # review: does this make sense? + localRecipients = lib.mkIf (cfg.lists != [ ]) cfg.lists; + }; + systemd.services = let commonServiceConfig = { + # We would have liked to use DynamicUser, but since the default + # database is SQLite and lives in StateDirectory, and that same + # database needs to be readable from the postfix service, this + # isn't trivial to do. + User = "schleuder"; + StateDirectory = "schleuder"; + StateDirectoryMode = "0700"; + }; in + { + schleuder-init = { + serviceConfig = commonServiceConfig // { + ExecStartPre = lib.mkIf (cfg.extraSettingsFile != null) [ + "+${configScript}" + ]; + ExecStart = [ "${pkgs.schleuder}/bin/schleuder install" ]; + Type = "oneshot"; + }; + }; + schleuder-api-daemon = { + after = [ "local-fs.target" "network.target" "schleuder-init.service" ]; + wantedBy = [ "multi-user.target" ]; + requires = [ "schleuder-init.service" ]; + serviceConfig = commonServiceConfig // { + ExecStart = [ "${pkgs.schleuder}/bin/schleuder-api-daemon" ]; + }; + }; + schleuder-weekly-key-maintenance = { + after = [ "local-fs.target" "network.target" ]; + startAt = "weekly"; + serviceConfig = commonServiceConfig // { + ExecStart = [ + "${pkgs.schleuder}/bin/schleuder refresh_keys" + "${pkgs.schleuder}/bin/schleuder check_keys" + ]; + }; + }; + }; + + environment.etc."schleuder/schleuder.yml" = lib.mkIf (cfg.extraSettingsFile == null) { + source = settingsFormat.generate "schleuder.yml" cfg.settings; + }; + environment.etc."schleuder/list-defaults.yml".source = settingsFormat.generate "list-defaults.yml" cfg.listDefaults; + + services.schleuder = { + #lists_dir = "/var/lib/schleuder.lists"; + settings.filters_dir = lib.mkDefault "/var/lib/schleuder/filters"; + settings.keyword_handlers_dir = lib.mkDefault "/var/lib/schleuder/keyword_handlers"; + }; + }; +} diff --git a/nixos/modules/services/matrix/synapse.nix b/nixos/modules/services/matrix/synapse.nix index b3108484fae12..3d5d10cdf070b 100644 --- a/nixos/modules/services/matrix/synapse.nix +++ b/nixos/modules/services/matrix/synapse.nix @@ -191,12 +191,12 @@ in { settings = mkOption { default = {}; - description = '' + description = mdDoc '' The primary synapse configuration. See the - <link xlink:href="https://github.com/matrix-org/synapse/blob/v${cfg.package.version}/docs/sample_config.yaml">sample configuration</link> + [sample configuration](https://github.com/matrix-org/synapse/blob/v${cfg.package.version}/docs/sample_config.yaml) for possible values. - Secrets should be passed in by using the <literal>extraConfigFiles</literal> option. + Secrets should be passed in by using the `extraConfigFiles` option. ''; type = with types; submodule { freeformType = format.type; @@ -230,23 +230,23 @@ in { registration_shared_secret = mkOption { type = types.nullOr types.str; default = null; - description = '' + description = mdDoc '' If set, allows registration by anyone who also has the shared secret, even if registration is otherwise disabled. - Secrets should be passed in via <literal>extraConfigFiles</literal>! + Secrets should be passed in via `extraConfigFiles`! ''; }; macaroon_secret_key = mkOption { type = types.nullOr types.str; default = null; - description = '' + description = mdDoc '' Secret key for authentication tokens. If none is specified, the registration_shared_secret is used, if one is given; otherwise, a secret key is derived from the signing key. - Secrets should be passed in via <literal>extraConfigFiles</literal>! + Secrets should be passed in via `extraConfigFiles`! ''; }; @@ -620,10 +620,10 @@ in { example = literalExpression '' config.services.coturn.static-auth-secret ''; - description = '' + description = mdDoc '' The shared secret used to compute passwords for the TURN server. - Secrets should be passed in via <literal>extraConfigFiles</literal>! + Secrets should be passed in via `extraConfigFiles`! ''; }; diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix index 354278fad226b..5a5f488dc565b 100644 --- a/nixos/modules/services/misc/gollum.nix +++ b/nixos/modules/services/misc/gollum.nix @@ -47,7 +47,7 @@ in user-icons = mkOption { type = types.nullOr (types.enum [ "gravatar" "identicon" ]); default = null; - description = "User icons for history view"; + description = "Enable specific user icons for history view"; }; emoji = mkOption { @@ -68,6 +68,12 @@ in description = "Disable editing pages"; }; + local-time = mkOption { + type = types.bool; + default = false; + description = "Use the browser's local timezone instead of the server's for displaying dates."; + }; + branch = mkOption { type = types.str; default = "master"; @@ -123,6 +129,7 @@ in ${optionalString cfg.emoji "--emoji"} \ ${optionalString cfg.h1-title "--h1-title"} \ ${optionalString cfg.no-edit "--no-edit"} \ + ${optionalString cfg.local-time "--local-time"} \ ${optionalString (cfg.allowUploads != null) "--allow-uploads ${cfg.allowUploads}"} \ ${optionalString (cfg.user-icons != null) "--user-icons ${cfg.user-icons}"} \ ${cfg.stateDir} diff --git a/nixos/modules/services/monitoring/grafana-agent.nix b/nixos/modules/services/monitoring/grafana-agent.nix new file mode 100644 index 0000000000000..bbeda18464707 --- /dev/null +++ b/nixos/modules/services/monitoring/grafana-agent.nix @@ -0,0 +1,143 @@ +{ lib, pkgs, config, generators, ... }: +with lib; +let + cfg = config.services.grafana-agent; + settingsFormat = pkgs.formats.yaml { }; + configFile = settingsFormat.generate "grafana-agent.yaml" cfg.settings; +in +{ + meta = { + maintainers = with maintainers; [ flokli zimbatm ]; + }; + + options.services.grafana-agent = { + enable = mkEnableOption "grafana-agent"; + + package = mkOption { + type = types.package; + default = pkgs.grafana-agent; + defaultText = "pkgs.grafana-agent"; + description = "The grafana-agent package to use."; + }; + + credentials = mkOption { + description = '' + Credentials to load at service startup. Keys that are UPPER_SNAKE will be loaded as env vars. Values are absolute paths to the credentials. + ''; + type = types.attrsOf types.str; + default = { }; + + example = { + logs_remote_write_password = "/run/keys/grafana_agent_logs_remote_write_password"; + LOGS_REMOTE_WRITE_URL = "/run/keys/grafana_agent_logs_remote_write_url"; + LOGS_REMOTE_WRITE_USERNAME = "/run/keys/grafana_agent_logs_remote_write_username"; + metrics_remote_write_password = "/run/keys/grafana_agent_metrics_remote_write_password"; + METRICS_REMOTE_WRITE_URL = "/run/keys/grafana_agent_metrics_remote_write_url"; + METRICS_REMOTE_WRITE_USERNAME = "/run/keys/grafana_agent_metrics_remote_write_username"; + }; + }; + + settings = mkOption { + description = '' + Configuration for <package>grafana-agent</package>. + + See https://grafana.com/docs/agent/latest/configuration/ + ''; + + type = types.submodule { + freeformType = settingsFormat.type; + }; + + default = { + metrics = { + wal_directory = "\${STATE_DIRECTORY}"; + global.scrape_interval = "5s"; + }; + integrations = { + agent.enabled = true; + agent.scrape_integration = true; + node_exporter.enabled = true; + replace_instance_label = true; + }; + }; + + example = { + metrics.global.remote_write = [{ + url = "\${METRICS_REMOTE_WRITE_URL}"; + basic_auth.username = "\${METRICS_REMOTE_WRITE_USERNAME}"; + basic_auth.password_file = "\${CREDENTIALS_DIRECTORY}/metrics_remote_write_password"; + }]; + logs.configs = [{ + name = "default"; + scrape_configs = [ + { + job_name = "journal"; + journal = { + max_age = "12h"; + labels.job = "systemd-journal"; + }; + relabel_configs = [ + { + source_labels = [ "__journal__systemd_unit" ]; + target_label = "systemd_unit"; + } + { + source_labels = [ "__journal__hostname" ]; + target_label = "nodename"; + } + { + source_labels = [ "__journal_syslog_identifier" ]; + target_label = "syslog_identifier"; + } + ]; + } + ]; + positions.filename = "\${STATE_DIRECTORY}/loki_positions.yaml"; + clients = [{ + url = "\${LOGS_REMOTE_WRITE_URL}"; + basic_auth.username = "\${LOGS_REMOTE_WRITE_USERNAME}"; + basic_auth.password_file = "\${CREDENTIALS_DIRECTORY}/logs_remote_write_password"; + }]; + }]; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.grafana-agent = { + wantedBy = [ "multi-user.target" ]; + script = '' + set -euo pipefail + shopt -u nullglob + + # Load all credentials into env if they are in UPPER_SNAKE form. + if [[ -n "''${CREDENTIALS_DIRECTORY:-}" ]]; then + for file in "$CREDENTIALS_DIRECTORY"/*; do + key=$(basename "$file") + if [[ $key =~ ^[A-Z0-9_]+$ ]]; then + echo "Environ $key" + export "$key=$(< "$file")" + fi + done + fi + + # We can't use Environment=HOSTNAME=%H, as it doesn't include the domain part. + export HOSTNAME=$(< /proc/sys/kernel/hostname) + + exec ${cfg.package}/bin/agent -config.expand-env -config.file ${configFile} + ''; + serviceConfig = { + Restart = "always"; + DynamicUser = true; + RestartSec = 2; + SupplementaryGroups = [ + # allow to read the systemd journal for loki log forwarding + "systemd-journal" + ]; + StateDirectory = "grafana-agent"; + LoadCredential = lib.mapAttrsToList (key: value: "${key}:${value}") cfg.credentials; + Type = "simple"; + }; + }; + }; +} diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index 497d46741381b..68b4796f4f4ec 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -124,6 +124,11 @@ let default = 1; description = "Org id. will default to orgId 1 if not specified."; }; + uid = mkOption { + type = types.nullOr types.str; + default = null; + description = "Custom UID which can be used to reference this datasource in other parts of the configuration, if not specified will be generated automatically."; + }; url = mkOption { type = types.str; description = "Url of the datasource."; diff --git a/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix b/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix index 4d3c1fa267e5f..53509b7a385b4 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix @@ -74,11 +74,13 @@ in }; }; serviceOpts = { + after = mkIf cfg.systemd.enable [ cfg.systemd.unit ]; serviceConfig = { DynamicUser = false; # By default, each prometheus exporter only gets AF_INET & AF_INET6, # but AF_UNIX is needed to read from the `showq`-socket. RestrictAddressFamilies = [ "AF_UNIX" ]; + SupplementaryGroups = mkIf cfg.systemd.enable [ "systemd-journal" ]; ExecStart = '' ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix b/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix index d4aa69629ec89..2d329a1af1cbc 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix @@ -57,9 +57,9 @@ in { ${pkgs.prometheus-wireguard-exporter}/bin/prometheus_wireguard_exporter \ -p ${toString cfg.port} \ -l ${cfg.listenAddress} \ - ${optionalString cfg.verbose "-v"} \ - ${optionalString cfg.singleSubnetPerField "-s"} \ - ${optionalString cfg.withRemoteIp "-r"} \ + ${optionalString cfg.verbose "-v true"} \ + ${optionalString cfg.singleSubnetPerField "-s true"} \ + ${optionalString cfg.withRemoteIp "-r true"} \ ${optionalString (cfg.wireguardConfig != null) "-n ${escapeShellArg cfg.wireguardConfig}"} ''; RestrictAddressFamilies = [ diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix index 395b9788855ff..a5f8f55a682c9 100644 --- a/nixos/modules/services/network-filesystems/ipfs.nix +++ b/nixos/modules/services/network-filesystems/ipfs.nix @@ -257,7 +257,7 @@ in '' + optionalString cfg.autoMigrate '' ${pkgs.ipfs-migrator}/bin/fs-repo-migrations -to '${cfg.package.repoVersion}' -y '' + '' - ipfs --offline config profile apply ${profile} + ipfs --offline config profile apply ${profile} >/dev/null fi '' + optionalString cfg.autoMount '' ipfs --offline config Mounts.FuseAllowOther --json true diff --git a/nixos/modules/services/networking/bitlbee.nix b/nixos/modules/services/networking/bitlbee.nix index 8bf04e3a1a23c..f76cffc79bfa4 100644 --- a/nixos/modules/services/networking/bitlbee.nix +++ b/nixos/modules/services/networking/bitlbee.nix @@ -174,6 +174,7 @@ in serviceConfig = { DynamicUser = true; StateDirectory = "bitlbee"; + ReadWritePaths = [ cfg.configDir ]; ExecStart = "${bitlbeePkg}/sbin/bitlbee -F -n -c ${bitlbeeConfig}"; }; }; diff --git a/nixos/modules/services/networking/expressvpn.nix b/nixos/modules/services/networking/expressvpn.nix new file mode 100644 index 0000000000000..d8ae6528a4d4e --- /dev/null +++ b/nixos/modules/services/networking/expressvpn.nix @@ -0,0 +1,29 @@ +{ config, lib, pkgs, ... }: + +with lib; +{ + options.services.expressvpn.enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable the ExpressVPN daemon. + ''; + }; + + config = mkIf config.services.expressvpn.enable { + boot.kernelModules = [ "tun" ]; + + systemd.services.expressvpn = { + description = "ExpressVPN Daemon"; + serviceConfig = { + ExecStart = "${pkgs.expressvpn}/bin/expressvpnd"; + Restart = "on-failure"; + RestartSec = 5; + }; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "network-online.target" ]; + }; + }; + + meta.maintainers = with maintainers; [ yureien ]; +} diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix index 256d9457d3960..70c6725d1035c 100644 --- a/nixos/modules/services/networking/mosquitto.nix +++ b/nixos/modules/services/networking/mosquitto.nix @@ -54,10 +54,10 @@ let hashedPassword = mkOption { type = uniq (nullOr str); default = null; - description = '' + description = mdDoc '' Specifies the hashed password for the MQTT User. - To generate hashed password install <literal>mosquitto</literal> - package and use <literal>mosquitto_passwd</literal>. + To generate hashed password install `mosquitto` + package and use `mosquitto_passwd`. ''; }; @@ -65,11 +65,11 @@ let type = uniq (nullOr types.path); example = "/path/to/file"; default = null; - description = '' + description = mdDoc '' Specifies the path to a file containing the hashed password for the MQTT user. - To generate hashed password install <literal>mosquitto</literal> - package and use <literal>mosquitto_passwd</literal>. + To generate hashed password install `mosquitto` + package and use `mosquitto_passwd`. ''; }; @@ -155,24 +155,24 @@ let options = { plugin = mkOption { type = path; - description = '' - Plugin path to load, should be a <literal>.so</literal> file. + description = mdDoc '' + Plugin path to load, should be a `.so` file. ''; }; denySpecialChars = mkOption { type = bool; - description = '' - Automatically disallow all clients using <literal>#</literal> - or <literal>+</literal> in their name/id. + description = mdDoc '' + Automatically disallow all clients using `#` + or `+` in their name/id. ''; default = true; }; options = mkOption { type = attrsOf optionType; - description = '' - Options for the auth plugin. Each key turns into a <literal>auth_opt_*</literal> + description = mdDoc '' + Options for the auth plugin. Each key turns into a `auth_opt_*` line in the config. ''; default = {}; @@ -239,8 +239,8 @@ let address = mkOption { type = nullOr str; - description = '' - Address to listen on. Listen on <literal>0.0.0.0</literal>/<literal>::</literal> + description = mdDoc '' + Address to listen on. Listen on `0.0.0.0`/`::` when unset. ''; default = null; @@ -248,10 +248,10 @@ let authPlugins = mkOption { type = listOf authPluginOptions; - description = '' + description = mdDoc '' Authentication plugin to attach to this listener. - Refer to the <link xlink:href="https://mosquitto.org/man/mosquitto-conf-5.html"> - mosquitto.conf documentation</link> for details on authentication plugins. + Refer to the [mosquitto.conf documentation](https://mosquitto.org/man/mosquitto-conf-5.html) + for details on authentication plugins. ''; default = []; }; @@ -472,10 +472,10 @@ let includeDirs = mkOption { type = listOf path; - description = '' + description = mdDoc '' Directories to be scanned for further config files to include. Directories will processed in the order given, - <literal>*.conf</literal> files in the directory will be + `*.conf` files in the directory will be read in case-sensistive alphabetical order. ''; default = []; diff --git a/nixos/modules/services/networking/routedns.nix b/nixos/modules/services/networking/routedns.nix new file mode 100644 index 0000000000000..e0f5eedd2c8e5 --- /dev/null +++ b/nixos/modules/services/networking/routedns.nix @@ -0,0 +1,84 @@ +{ config +, lib +, pkgs +, ... +}: + +with lib; + +let + cfg = config.services.routedns; + settingsFormat = pkgs.formats.toml { }; +in +{ + options.services.routedns = { + enable = mkEnableOption "RouteDNS - DNS stub resolver, proxy and router"; + + settings = mkOption { + type = settingsFormat.type; + example = literalExpression '' + { + resolvers.cloudflare-dot = { + address = "1.1.1.1:853"; + protocol = "dot"; + }; + groups.cloudflare-cached = { + type = "cache"; + resolvers = ["cloudflare-dot"]; + }; + listeners.local-udp = { + address = "127.0.0.1:53"; + protocol = "udp"; + resolver = "cloudflare-cached"; + }; + listeners.local-tcp = { + address = "127.0.0.1:53"; + protocol = "tcp"; + resolver = "cloudflare-cached"; + }; + } + ''; + description = '' + Configuration for RouteDNS, see <link xlink:href="https://github.com/folbricht/routedns/blob/master/doc/configuration.md"/> + for more information. + ''; + }; + + configFile = mkOption { + default = settingsFormat.generate "routedns.toml" cfg.settings; + defaultText = "A RouteDNS configuration file automatically generated by values from services.routedns.*"; + type = types.path; + example = literalExpression ''"''${pkgs.routedns}/cmd/routedns/example-config/use-case-1.toml"''; + description = "Path to RouteDNS TOML configuration file."; + }; + + package = mkOption { + default = pkgs.routedns; + defaultText = literalExpression "pkgs.routedns"; + type = types.package; + description = "RouteDNS package to use."; + }; + }; + + config = mkIf cfg.enable { + systemd.services.routedns = { + description = "RouteDNS - DNS stub resolver, proxy and router"; + after = [ "network.target" ]; # in case a bootstrap resolver is used, this might fail a few times until the respective server is actually reachable + wantedBy = [ "multi-user.target" ]; + wants = [ "network.target" ]; + startLimitIntervalSec = 30; + startLimitBurst = 5; + serviceConfig = { + Restart = "on-failure"; + RestartSec = "5s"; + LimitNPROC = 512; + LimitNOFILE = 1048576; + DynamicUser = true; + AmbientCapabilities = "CAP_NET_BIND_SERVICE"; + NoNewPrivileges = true; + ExecStart = "${getBin cfg.package}/bin/routedns -l 4 ${cfg.configFile}"; + }; + }; + }; + meta.maintainers = with maintainers; [ jsimonetti ]; +} diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index 3a3d4c80ecff4..6a90f28dc5f7b 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -72,39 +72,39 @@ in { cert = mkOption { type = types.nullOr types.str; default = null; - description = '' - Path to the <literal>cert.pem</literal> file, which will be copied into Syncthing's - <link linkend="opt-services.syncthing.configDir">configDir</link>. + description = mdDoc '' + Path to the `cert.pem` file, which will be copied into Syncthing's + [configDir](#opt-services.syncthing.configDir). ''; }; key = mkOption { type = types.nullOr types.str; default = null; - description = '' - Path to the <literal>key.pem</literal> file, which will be copied into Syncthing's - <link linkend="opt-services.syncthing.configDir">configDir</link>. + description = mdDoc '' + Path to the `key.pem` file, which will be copied into Syncthing's + [configDir](#opt-services.syncthing.configDir). ''; }; overrideDevices = mkOption { type = types.bool; default = true; - description = '' + description = mdDoc '' Whether to delete the devices which are not configured via the - <link linkend="opt-services.syncthing.devices">devices</link> option. - If set to <literal>false</literal>, devices added via the web + [devices](#opt-services.syncthing.devices) option. + If set to `false`, devices added via the web interface will persist and will have to be deleted manually. ''; }; devices = mkOption { default = {}; - description = '' + description = mdDoc '' Peers/devices which Syncthing should communicate with. Note that you can still add devices manually, but those changes - will be reverted on restart if <link linkend="opt-services.syncthing.overrideDevices">overrideDevices</link> + will be reverted on restart if [overrideDevices](#opt-services.syncthing.overrideDevices) is enabled. ''; example = { @@ -135,27 +135,27 @@ in { id = mkOption { type = types.str; - description = '' - The device ID. See <link xlink:href="https://docs.syncthing.net/dev/device-ids.html"/>. + description = mdDoc '' + The device ID. See <https://docs.syncthing.net/dev/device-ids.html>. ''; }; introducer = mkOption { type = types.bool; default = false; - description = '' + description = mdDoc '' Whether the device should act as an introducer and be allowed to add folders on this computer. - See <link xlink:href="https://docs.syncthing.net/users/introducer.html"/>. + See <https://docs.syncthing.net/users/introducer.html>. ''; }; autoAcceptFolders = mkOption { type = types.bool; default = false; - description = '' + description = mdDoc '' Automatically create or share folders that this device advertises at the default path. - See <link xlink:href="https://docs.syncthing.net/users/config.html?highlight=autoaccept#config-file-format"/>. + See <https://docs.syncthing.net/users/config.html?highlight=autoaccept#config-file-format>. ''; }; @@ -166,21 +166,21 @@ in { overrideFolders = mkOption { type = types.bool; default = true; - description = '' + description = mdDoc '' Whether to delete the folders which are not configured via the - <link linkend="opt-services.syncthing.folders">folders</link> option. - If set to <literal>false</literal>, folders added via the web + [folders](#opt-services.syncthing.folders) option. + If set to `false`, folders added via the web interface will persist and will have to be deleted manually. ''; }; folders = mkOption { default = {}; - description = '' + description = mdDoc '' Folders which should be shared by Syncthing. Note that you can still add devices manually, but those changes - will be reverted on restart if <link linkend="opt-services.syncthing.overrideDevices">overrideDevices</link> + will be reverted on restart if [overrideDevices](#opt-services.syncthing.overrideDevices) is enabled. ''; example = literalExpression '' @@ -231,18 +231,18 @@ in { devices = mkOption { type = types.listOf types.str; default = []; - description = '' + description = mdDoc '' The devices this folder should be shared with. Each device must - be defined in the <link linkend="opt-services.syncthing.devices">devices</link> option. + be defined in the [devices](#opt-services.syncthing.devices) option. ''; }; versioning = mkOption { default = null; - description = '' + description = mdDoc '' How to keep changed/deleted files with Syncthing. There are 4 different types of versioning with different parameters. - See <link xlink:href="https://docs.syncthing.net/users/versioning.html"/>. + See <https://docs.syncthing.net/users/versioning.html>. ''; example = literalExpression '' [ @@ -284,17 +284,17 @@ in { options = { type = mkOption { type = enum [ "external" "simple" "staggered" "trashcan" ]; - description = '' + description = mdDoc '' The type of versioning. - See <link xlink:href="https://docs.syncthing.net/users/versioning.html"/>. + See <https://docs.syncthing.net/users/versioning.html>. ''; }; params = mkOption { type = attrsOf (either str path); - description = '' + description = mdDoc '' The parameters for versioning. Structure depends on - <link linkend="opt-services.syncthing.folders._name_.versioning.type">versioning.type</link>. - See <link xlink:href="https://docs.syncthing.net/users/versioning.html"/>. + [versioning.type](#opt-services.syncthing.folders._name_.versioning.type). + See <https://docs.syncthing.net/users/versioning.html>. ''; }; }; @@ -345,9 +345,9 @@ in { ignoreDelete = mkOption { type = types.bool; default = false; - description = '' + description = mdDoc '' Whether to skip deleting files that are deleted by peers. - See <link xlink:href="https://docs.syncthing.net/advanced/folder-ignoredelete.html"/>. + See <https://docs.syncthing.net/advanced/folder-ignoredelete.html>. ''; }; }; @@ -357,9 +357,9 @@ in { extraOptions = mkOption { type = types.addCheck (pkgs.formats.json {}).type isAttrs; default = {}; - description = '' + description = mdDoc '' Extra configuration options for Syncthing. - See <link xlink:href="https://docs.syncthing.net/users/config.html"/>. + See <https://docs.syncthing.net/users/config.html>. ''; example = { options.localAnnounceEnabled = false; @@ -387,9 +387,9 @@ in { type = types.str; default = defaultUser; example = "yourUser"; - description = '' + description = mdDoc '' The user to run Syncthing as. - By default, a user named <literal>${defaultUser}</literal> will be created. + By default, a user named `${defaultUser}` will be created. ''; }; @@ -397,9 +397,9 @@ in { type = types.str; default = defaultGroup; example = "yourGroup"; - description = '' + description = mdDoc '' The group to run Syncthing under. - By default, a group named <literal>${defaultGroup}</literal> will be created. + By default, a group named `${defaultGroup}` will be created. ''; }; @@ -407,11 +407,11 @@ in { type = with types; nullOr str; default = null; example = "socks5://address.com:1234"; - description = '' + description = mdDoc '' Overwrites the all_proxy environment variable for the Syncthing process to the given value. This is normally used to let Syncthing connect through a SOCKS5 proxy server. - See <link xlink:href="https://docs.syncthing.net/users/proxying.html"/>. + See <https://docs.syncthing.net/users/proxying.html>. ''; }; @@ -432,25 +432,13 @@ in { The path where the settings and keys will exist. ''; default = cfg.dataDir + optionalString cond "/.config/syncthing"; - defaultText = literalDocBook '' - <variablelist> - <varlistentry> - <term><literal>stateVersion >= 19.03</literal></term> - <listitem> - <programlisting> - config.${opt.dataDir} + "/.config/syncthing" - </programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term>otherwise</term> - <listitem> - <programlisting> - config.${opt.dataDir} - </programlisting> - </listitem> - </varlistentry> - </variablelist> + defaultText = literalMD '' + * if `stateVersion >= 19.03`: + + config.${opt.dataDir} + "/.config/syncthing" + * otherwise: + + config.${opt.dataDir} ''; }; diff --git a/nixos/modules/services/networking/tailscale.nix b/nixos/modules/services/networking/tailscale.nix index 0133874d0e0d0..f84252289abff 100644 --- a/nixos/modules/services/networking/tailscale.nix +++ b/nixos/modules/services/networking/tailscale.nix @@ -6,6 +6,7 @@ let cfg = config.services.tailscale; firewallOn = config.networking.firewall.enable; rpfMode = config.networking.firewall.checkReversePath; + isNetworkd = config.networking.useNetworkd; rpfIsStrict = rpfMode == true || rpfMode == "strict"; in { meta.maintainers = with maintainers; [ danderson mbaillie twitchyliquid64 ]; @@ -69,5 +70,17 @@ in { # linux distros. stopIfChanged = false; }; + + networking.dhcpcd.denyInterfaces = [ cfg.interfaceName ]; + + systemd.network.networks."50-tailscale" = mkIf isNetworkd { + matchConfig = { + Name = cfg.interfaceName; + }; + linkConfig = { + Unmanaged = true; + ActivationPolicy = "manual"; + }; + }; }; } diff --git a/nixos/modules/services/networking/trickster.nix b/nixos/modules/services/networking/trickster.nix index e48bba8fa587f..ac260a14d9a2d 100644 --- a/nixos/modules/services/networking/trickster.nix +++ b/nixos/modules/services/networking/trickster.nix @@ -6,6 +6,9 @@ let cfg = config.services.trickster; in { + imports = [ + (mkRenamedOptionModule [ "services" "trickster" "origin" ] [ "services" "trickster" "origin-url" ]) + ]; options = { services.trickster = { @@ -58,11 +61,19 @@ in ''; }; - origin = mkOption { + origin-type = mkOption { + type = types.enum [ "prometheus" "influxdb" ]; + default = "prometheus"; + description = '' + Type of origin (prometheus, influxdb) + ''; + }; + + origin-url = mkOption { type = types.str; default = "http://prometheus:9090"; description = '' - URL to the Prometheus Origin. Enter it like you would in grafana, e.g., http://prometheus:9090 (default http://prometheus:9090). + URL to the Origin. Enter it like you would in grafana, e.g., http://prometheus:9090 (default http://prometheus:9090). ''; }; @@ -87,7 +98,7 @@ in config = mkIf cfg.enable { systemd.services.trickster = { - description = "Dashboard Accelerator for Prometheus"; + description = "Reverse proxy cache and time series dashboard accelerator"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { @@ -96,7 +107,8 @@ in ${cfg.package}/bin/trickster \ -log-level ${cfg.log-level} \ -metrics-port ${toString cfg.metrics-port} \ - -origin ${cfg.origin} \ + -origin-type ${cfg.origin-type} \ + -origin-url ${cfg.origin-url} \ -proxy-port ${toString cfg.proxy-port} \ ${optionalString (cfg.configFile != null) "-config ${cfg.configFile}"} \ ${optionalString (cfg.profiler-port != null) "-profiler-port ${cfg.profiler-port}"} \ diff --git a/nixos/modules/services/networking/wg-quick.nix b/nixos/modules/services/networking/wg-quick.nix index 0b3815d0cc628..236d3f452e7e6 100644 --- a/nixos/modules/services/networking/wg-quick.nix +++ b/nixos/modules/services/networking/wg-quick.nix @@ -10,6 +10,18 @@ let interfaceOpts = { ... }: { options = { + + configFile = mkOption { + example = "/secret/wg0.conf"; + default = null; + type = with types; nullOr str; + description = '' + wg-quick .conf file, describing the interface. + This overrides any other configuration interface configuration options. + See wg-quick manpage for more details. + ''; + }; + address = mkOption { example = [ "192.168.2.1/24" ]; default = []; @@ -205,7 +217,7 @@ let writeScriptFile = name: text: ((pkgs.writeShellScriptBin name text) + "/bin/${name}"); generateUnit = name: values: - assert assertMsg ((values.privateKey != null) != (values.privateKeyFile != null)) "Only one of privateKey or privateKeyFile may be set"; + assert assertMsg (values.configFile != null || ((values.privateKey != null) != (values.privateKeyFile != null))) "Only one of privateKey, configFile or privateKeyFile may be set"; let preUpFile = if values.preUp != "" then writeScriptFile "preUp.sh" values.preUp else null; postUp = @@ -247,7 +259,12 @@ let optionalString (peer.allowedIPs != []) "AllowedIPs = ${concatStringsSep "," peer.allowedIPs}\n" ) values.peers; }; - configPath = "${configDir}/${name}.conf"; + configPath = + if values.configFile != null then + # This uses bind-mounted private tmp folder (/tmp/systemd-private-***) + "/tmp/${name}.conf" + else + "${configDir}/${name}.conf"; in nameValuePair "wg-quick-${name}" { @@ -265,9 +282,17 @@ let script = '' ${optionalString (!config.boot.isContainer) "modprobe wireguard"} + ${optionalString (values.configFile != null) '' + cp ${values.configFile} ${configPath} + ''} wg-quick up ${configPath} ''; + serviceConfig = { + # Used to privately store renamed copies of external config files during activation + PrivateTmp = true; + }; + preStop = '' wg-quick down ${configPath} ''; diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix index c2e1d37e28bf4..5a7975ae17828 100644 --- a/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixos/modules/services/networking/wpa_supplicant.nix @@ -114,7 +114,7 @@ let script = '' - ${optionalString configIsGenerated '' + ${optionalString (configIsGenerated && !cfg.allowAuxiliaryImperativeNetworks) '' if [ -f /etc/wpa_supplicant.conf ]; then echo >&2 "<3>/etc/wpa_supplicant.conf present but ignored. Generated ${configFile} is used instead." fi diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix index 8277f493639c2..756e0ee93b219 100644 --- a/nixos/modules/services/security/vaultwarden/default.nix +++ b/nixos/modules/services/security/vaultwarden/default.nix @@ -62,20 +62,52 @@ in { default = {}; example = literalExpression '' { - domain = "https://bw.domain.tld:8443"; - signupsAllowed = true; - rocketPort = 8222; - rocketLog = "critical"; + DOMAIN = "https://bitwarden.example.com"; + SIGNUPS_ALLOWED = false; + + # Vaultwarden currently recommends running behind a reverse proxy + # (nginx or similar) for TLS termination, see + # https://github.com/dani-garcia/vaultwarden/wiki/Hardening-Guide#reverse-proxying + # > you should avoid enabling HTTPS via vaultwarden's built-in Rocket TLS support, + # > especially if your instance is publicly accessible. + # + # A suitable NixOS nginx reverse proxy example config might be: + # + # services.nginx.virtualHosts."bitwarden.example.com" = { + # enableACME = true; + # forceSSL = true; + # locations."/" = { + # proxyPass = "http://127.0.0.1:''${toString config.services.vaultwarden.config.ROCKET_PORT}"; + # }; + # }; + ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_PORT = 8222; + + ROCKET_LOG = "critical"; + + # This example assumes a mailserver running on localhost, + # thus without transport encryption. + # If you use an external mail server, follow: + # https://github.com/dani-garcia/vaultwarden/wiki/SMTP-configuration + SMTP_HOST = "127.0.0.1"; + SMTP_PORT = 25; + SMTP_SSL = false; + + SMTP_FROM = "admin@bitwarden.example.com"; + SMTP_FROM_NAME = "example.com Bitwarden server"; } ''; description = '' The configuration of vaultwarden is done through environment variables, - therefore the names are converted from camel case (e.g. disable2FARemember) - to upper case snake case (e.g. DISABLE_2FA_REMEMBER). + therefore it is recommended to use upper snake case (e.g. <envar>DISABLE_2FA_REMEMBER</envar>). + + However, camel case (e.g. <literal>disable2FARemember</literal>) is also supported: + The NixOS module will convert it automatically to + upper case snake case (e.g. <envar>DISABLE_2FA_REMEMBER</envar>). In this conversion digits (0-9) are handled just like upper case characters, - so foo2 would be converted to FOO_2. - Names already in this format remain unchanged, so FOO2 remains FOO2 if passed as such, - even though foo2 would have been converted to FOO_2. + so <literal>foo2</literal> would be converted to <envar>FOO_2</envar>. + Names already in this format remain unchanged, so <literal>FOO2</literal> remains <literal>FOO2</literal> if passed as such, + even though <literal>foo2</literal> would have been converted to <envar>FOO_2</envar>. This allows working around any potential future conflicting naming conventions. Based on the attributes passed to this config option an environment file will be generated @@ -83,13 +115,16 @@ in { The available configuration options can be found in <link xlink:href="https://github.com/dani-garcia/vaultwarden/blob/${vaultwarden.version}/.env.template">the environment template file</link>. + + See <xref linkend="opt-services.vaultwarden.environmentFile" /> for how + to set up access to the Admin UI to invite initial users. ''; }; environmentFile = mkOption { type = with types; nullOr path; default = null; - example = "/root/vaultwarden.env"; + example = "/var/lib/vaultwarden.env"; description = '' Additional environment file as defined in <citerefentry> <refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum> @@ -100,6 +135,23 @@ in { Note that this file needs to be available on the host on which <literal>vaultwarden</literal> is running. + + As a concrete example, to make the Admin UI available + (from which new users can be invited initially), + the secret <envar>ADMIN_TOKEN</envar> needs to be defined as described + <link xlink:href="https://github.com/dani-garcia/vaultwarden/wiki/Enabling-admin-page">here</link>. + Setting <literal>environmentFile</literal> to <literal>/var/lib/vaultwarden.env</literal> + and ensuring permissions with e.g. + <literal>chown vaultwarden:vaultwarden /var/lib/vaultwarden.env</literal> + (the <literal>vaultwarden</literal> user will only exist after activating with + <literal>enable = true;</literal> before this), we can set the contents of the file to have + contents such as: + +<programlisting> +# Admin secret token, see +# https://github.com/dani-garcia/vaultwarden/wiki/Enabling-admin-page +ADMIN_TOKEN=...copy-paste a unique generated secret token here... +</programlisting> ''; }; diff --git a/nixos/modules/services/web-apps/hedgedoc.nix b/nixos/modules/services/web-apps/hedgedoc.nix index 22270609dbccb..0310c15a4d27e 100644 --- a/nixos/modules/services/web-apps/hedgedoc.nix +++ b/nixos/modules/services/web-apps/hedgedoc.nix @@ -1031,7 +1031,8 @@ in ''; serviceConfig = { WorkingDirectory = cfg.workDir; - StateDirectory = [ cfg.workDir cfg.configuration.uploadsPath ]; + StateDirectory = [ (builtins.replaceStrings [ "/var/lib/" ] [ "" ] cfg.workDir) ]; + ReadWritePaths = [ cfg.configuration.uploadsPath ]; ExecStart = "${cfg.package}/bin/hedgedoc"; EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; Environment = [ diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix index 9aa38ab25c9a3..c441a2a7764e2 100644 --- a/nixos/modules/services/web-apps/tt-rss.nix +++ b/nixos/modules/services/web-apps/tt-rss.nix @@ -534,6 +534,7 @@ let services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") { ${poolName} = { inherit (cfg) user; + phpPackage = pkgs.php80; settings = mapAttrs (name: mkDefault) { "listen.owner" = "nginx"; "listen.group" = "nginx"; diff --git a/nixos/modules/services/x11/desktop-managers/gnome.nix b/nixos/modules/services/x11/desktop-managers/gnome.nix index e7e626c66f021..ff9d08ea99701 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome.nix @@ -189,7 +189,6 @@ in Note that this should be a last resort; patching the package is preferred (see GPaste). ''; - apply = list: list ++ [ pkgs.gnome.gnome-shell pkgs.gnome.gnome-shell-extensions ]; }; favoriteAppsOverride = mkOption { @@ -367,6 +366,10 @@ in services.upower.enable = config.powerManagement.enable; services.xserver.libinput.enable = mkDefault true; # for controlling touchpad settings via gnome control center + # Explicitly enabled since GNOME will be severely broken without these. + xdg.mime.enable = true; + xdg.icons.enable = true; + xdg.portal.enable = true; xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gnome @@ -400,6 +403,18 @@ in }) (mkIf serviceCfg.core-shell.enable { + services.xserver.desktopManager.gnome.sessionPath = + let + mandatoryPackages = [ + pkgs.gnome.gnome-shell + ]; + optionalPackages = [ + pkgs.gnome.gnome-shell-extensions + ]; + in + mandatoryPackages + ++ utils.removePackagesByName optionalPackages config.environment.gnome.excludePackages; + services.colord.enable = mkDefault true; services.gnome.chrome-gnome-shell.enable = mkDefault true; services.gnome.glib-networking.enable = true; @@ -452,26 +467,31 @@ in ]; # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-shell.bst - environment.systemPackages = with pkgs.gnome; [ - adwaita-icon-theme - nixos-background-info - gnome-backgrounds - gnome-bluetooth - gnome-color-manager - gnome-control-center - gnome-shell - gnome-shell-extensions - gnome-themes-extra - pkgs.gnome-tour # GNOME Shell detects the .desktop file on first log-in. - pkgs.gnome-user-docs - pkgs.orca - pkgs.glib # for gsettings - pkgs.gnome-menus - pkgs.gtk3.out # for gtk-launch - pkgs.hicolor-icon-theme - pkgs.shared-mime-info # for update-mime-database - pkgs.xdg-user-dirs # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/ - ]; + environment.systemPackages = + let + mandatoryPackages = with pkgs.gnome; [ + gnome-shell + ]; + optionalPackages = with pkgs.gnome; [ + adwaita-icon-theme + nixos-background-info + gnome-backgrounds + gnome-bluetooth + gnome-color-manager + gnome-control-center + gnome-shell-extensions + gnome-themes-extra + pkgs.gnome-tour # GNOME Shell detects the .desktop file on first log-in. + pkgs.gnome-user-docs + pkgs.orca + pkgs.glib # for gsettings program + pkgs.gnome-menus + pkgs.gtk3.out # for gtk-launch program + pkgs.xdg-user-dirs # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/ + ]; + in + mandatoryPackages + ++ utils.removePackagesByName optionalPackages config.environment.gnome.excludePackages; }) # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-utilities.bst diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix index 083b12193dab0..d04e565f7d310 100644 --- a/nixos/modules/services/x11/desktop-managers/pantheon.nix +++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix @@ -50,10 +50,6 @@ in Note that this should be a last resort; patching the package is preferred (see GPaste). ''; - apply = list: list ++ - [ - pkgs.pantheon.pantheon-agent-geoclue2 - ]; }; extraWingpanelIndicators = mkOption { @@ -96,6 +92,9 @@ in config = mkMerge [ (mkIf cfg.enable { + services.xserver.desktopManager.pantheon.sessionPath = utils.removePackagesByName [ + pkgs.pantheon.pantheon-agent-geoclue2 + ] config.environment.pantheon.excludePackages; services.xserver.displayManager.sessionPackages = [ pkgs.pantheon.elementary-session-settings ]; @@ -177,19 +176,28 @@ in networking.networkmanager.enable = mkDefault true; # Global environment - environment.systemPackages = with pkgs; [ + environment.systemPackages = (with pkgs.pantheon; [ + elementary-session-settings + elementary-settings-daemon + gala + gnome-settings-daemon + (switchboard-with-plugs.override { + plugs = cfg.extraSwitchboardPlugs; + }) + (wingpanel-with-indicators.override { + indicators = cfg.extraWingpanelIndicators; + }) + ]) ++ utils.removePackagesByName ((with pkgs; [ desktop-file-utils - glib + glib # for gsettings program gnome-menus gnome.adwaita-icon-theme - gtk3.out - hicolor-icon-theme + gtk3.out # for gtk-launch program onboard qgnomeplatform - shared-mime-info sound-theme-freedesktop - xdg-user-dirs - ] ++ (with pkgs.pantheon; [ + xdg-user-dirs # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/ + ]) ++ (with pkgs.pantheon; [ # Artwork elementary-gtk-theme elementary-icon-theme @@ -199,31 +207,21 @@ in # Desktop elementary-default-settings elementary-dock - elementary-session-settings elementary-shortcut-overlay - gala - (switchboard-with-plugs.override { - plugs = cfg.extraSwitchboardPlugs; - }) - (wingpanel-with-indicators.override { - indicators = cfg.extraWingpanelIndicators; - }) # Services elementary-capnet-assist elementary-notifications - elementary-settings-daemon - gnome-settings-daemon pantheon-agent-geoclue2 pantheon-agent-polkit - ]); - - programs.evince.enable = mkDefault true; - programs.file-roller.enable = mkDefault true; + ])) config.environment.pantheon.excludePackages; # Settings from elementary-default-settings environment.etc."gtk-3.0/settings.ini".source = "${pkgs.pantheon.elementary-default-settings}/etc/gtk-3.0/settings.ini"; + xdg.mime.enable = true; + xdg.icons.enable = true; + xdg.portal.enable = true; xdg.portal.extraPortals = with pkgs.pantheon; [ elementary-files @@ -271,6 +269,9 @@ in }) (mkIf serviceCfg.apps.enable { + programs.evince.enable = mkDefault true; + programs.file-roller.enable = mkDefault true; + environment.systemPackages = utils.removePackagesByName ([ pkgs.gnome.gnome-font-viewer ] ++ (with pkgs.pantheon; [ diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index 3ca044ad5bc85..144cb00e480ef 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -234,11 +234,11 @@ in (mkIf (cfg.enable || cfg.mobile.enable) { security.wrappers = { - kcheckpass = { + kscreenlocker_greet = { setuid = true; owner = "root"; group = "root"; - source = "${getBin libsForQt5.kscreenlocker}/libexec/kcheckpass"; + source = "${getBin libsForQt5.kscreenlocker}/libexec/kscreenlocker_greet"; }; start_kdeinit = { setuid = true; diff --git a/nixos/modules/services/x11/display-managers/xpra.nix b/nixos/modules/services/x11/display-managers/xpra.nix index c23e479140f09..1566e38da0839 100644 --- a/nixos/modules/services/x11/display-managers/xpra.nix +++ b/nixos/modules/services/x11/display-managers/xpra.nix @@ -26,6 +26,13 @@ in description = "Bind xpra to TCP"; }; + desktop = mkOption { + type = types.nullOr types.str; + default = null; + example = "gnome-shell"; + description = "Start a desktop environment instead of seamless mode"; + }; + auth = mkOption { type = types.str; default = "pam"; @@ -222,7 +229,7 @@ in services.xserver.displayManager.job.execCmd = '' ${optionalString (cfg.pulseaudio) "export PULSE_COOKIE=/run/pulse/.config/pulse/cookie"} - exec ${pkgs.xpra}/bin/xpra start \ + exec ${pkgs.xpra}/bin/xpra ${if cfg.desktop == null then "start" else "start-desktop --start=${cfg.desktop}"} \ --daemon=off \ --log-dir=/var/log \ --log-file=xpra.log \ diff --git a/nixos/modules/services/x11/picom.nix b/nixos/modules/services/x11/picom.nix index b40e20bcd3572..2eef71f71fcbf 100644 --- a/nixos/modules/services/x11/picom.nix +++ b/nixos/modules/services/x11/picom.nix @@ -51,6 +51,11 @@ in { imports = [ (mkAliasOptionModule [ "services" "compton" ] [ "services" "picom" ]) + (mkRemovedOptionModule [ "services" "picom" "refreshRate" ] '' + This option corresponds to `refresh-rate`, which has been unused + since picom v6 and was subsequently removed by upstream. + See https://github.com/yshui/picom/commit/bcbc410 + '') ]; options.services.picom = { @@ -235,15 +240,6 @@ in { ''; }; - refreshRate = mkOption { - type = types.ints.unsigned; - default = 0; - example = 60; - description = '' - Screen refresh rate (0 = automatically detect). - ''; - }; - settings = with types; let scalar = oneOf [ bool int float str ] @@ -306,7 +302,6 @@ in { # other options backend = cfg.backend; vsync = cfg.vSync; - refresh-rate = cfg.refreshRate; }; systemd.user.services.picom = { diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 679c5210a6b32..645fbc2b713a9 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -8,8 +8,6 @@ let cfg = config.systemd; - systemd = cfg.package; - inherit (systemdUtils.lib) generateUnits targetToUnit @@ -439,7 +437,7 @@ in system.build.units = cfg.units; - system.nssModules = [ systemd.out ]; + system.nssModules = [ cfg.package.out ]; system.nssDatabases = { hosts = (mkMerge [ (mkOrder 400 ["mymachines"]) # 400 to ensure it comes before resolve (which is mkBefore'd) @@ -453,7 +451,7 @@ in ]); }; - environment.systemPackages = [ systemd ]; + environment.systemPackages = [ cfg.package ]; environment.etc = let # generate contents for /etc/systemd/system-${type} from attrset of links and packages diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index 66fdc61d28357..dce72b36fc501 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -90,7 +90,7 @@ let bindsTo = [ "network-setup.service" ]; }; - networkSetup = + networkSetup = lib.mkIf (config.networking.resolvconf.enable || cfg.defaultGateway != null || cfg.defaultGateway6 != null) { description = "Networking Setup"; after = [ "network-pre.target" "systemd-udevd.service" "systemd-sysctl.service" ]; diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index 80808e0c08fa5..1657fabcd9b1c 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -59,15 +59,14 @@ in genericNetwork = override: let gateway = optional (cfg.defaultGateway != null && (cfg.defaultGateway.address or "") != "") cfg.defaultGateway.address ++ optional (cfg.defaultGateway6 != null && (cfg.defaultGateway6.address or "") != "") cfg.defaultGateway6.address; - in optionalAttrs (gateway != [ ]) { - routes = override [ - { + makeGateway = gateway: { routeConfig = { Gateway = gateway; GatewayOnLink = false; }; - } - ]; + }; + in optionalAttrs (gateway != [ ]) { + routes = override (map makeGateway gateway); } // optionalAttrs (domains != [ ]) { domains = override domains; }; @@ -89,20 +88,22 @@ in # more likely to result in interfaces being configured to # use DHCP when they shouldn't. - # We set RequiredForOnline to false, because it's fairly - # common for such devices to have multiple interfaces and - # only one of them to be connected (e.g. a laptop with - # ethernet and WiFi interfaces). Maybe one day networkd will - # support "any"-style RequiredForOnline... + # When wait-online.anyInterface is enabled, RequiredForOnline really + # means "sufficient for online", so we can enable it. + # Otherwise, don't block the network coming online because of default networks. matchConfig.Name = ["en*" "eth*"]; DHCP = "yes"; - linkConfig.RequiredForOnline = lib.mkDefault false; + linkConfig.RequiredForOnline = + lib.mkDefault config.systemd.network.wait-online.anyInterface; + networkConfig.IPv6PrivacyExtensions = "kernel"; }; networks."99-wireless-client-dhcp" = lib.mkIf cfg.useDHCP { # Like above, but this is much more likely to be correct. matchConfig.WLANInterfaceType = "station"; DHCP = "yes"; - linkConfig.RequiredForOnline = lib.mkDefault false; + linkConfig.RequiredForOnline = + lib.mkDefault config.systemd.network.wait-online.anyInterface; + networkConfig.IPv6PrivacyExtensions = "kernel"; # We also set the route metric to one more than the default # of 1024, so that Ethernet is preferred if both are # available. diff --git a/nixos/modules/virtualisation/lxc-container.nix b/nixos/modules/virtualisation/lxc-container.nix index 9816cc2332fbd..d3a2e0ed151d3 100644 --- a/nixos/modules/virtualisation/lxc-container.nix +++ b/nixos/modules/virtualisation/lxc-container.nix @@ -63,18 +63,18 @@ in default = {}; example = literalExpression '' { - # create /etc/hostname on container creation + # create /etc/hostname on container creation. also requires networking.hostName = "" to be set "hostname" = { enable = true; target = "/etc/hostname"; - template = builtins.writeFile "hostname.tpl" "{{ container.name }}"; + template = builtins.toFile "hostname.tpl" "{{ container.name }}"; when = [ "create" ]; }; # create /etc/nixos/hostname.nix with a configuration for keeping the hostname applied "hostname-nix" = { enable = true; target = "/etc/nixos/hostname.nix"; - template = builtins.writeFile "hostname-nix.tpl" "{ ... }: { networking.hostName = "{{ container.name }}"; }"; + template = builtins.toFile "hostname-nix.tpl" "{ ... }: { networking.hostName = \"{{ container.name }}\"; }"; # copy keeps the file updated when the container is changed when = [ "create" "copy" ]; }; @@ -82,7 +82,7 @@ in "configuration-nix" = { enable = true; target = "/etc/nixos/configuration.nix"; - template = builtins.writeFile "configuration-nix" "{{ config_get(\"user.user-data\", properties.default) }}"; + template = builtins.toFile "configuration-nix" "{{ config_get(\"user.user-data\", properties.default) }}"; when = [ "create" ]; }; }; diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix index 975eed10cd267..a999efcb44e64 100644 --- a/nixos/modules/virtualisation/xen-dom0.nix +++ b/nixos/modules/virtualisation/xen-dom0.nix @@ -23,12 +23,12 @@ in default = false; type = types.bool; description = - '' + mdDoc '' Setting this option enables the Xen hypervisor, a virtualisation technology that allows multiple virtual - machines, known as <emphasis>domains</emphasis>, to run + machines, known as *domains*, to run concurrently on the physical machine. NixOS runs as the - privileged <emphasis>Domain 0</emphasis>. This option + privileged *Domain 0*. This option requires a reboot to take effect. ''; }; |