refactor: change to litterate config
Configuration is now held by the `.org` files. All `.nix` files are tangled from the org-mode files.
This commit is contained in:
+21
-39
@@ -1,44 +1,26 @@
|
||||
{
|
||||
flake.modules.nixos.hardened = {
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.mySystem.boot.kernel;
|
||||
in {
|
||||
options.mySystem.boot.kernel.hardened = mkEnableOption "Enables hardened Linux kernel";
|
||||
|
||||
config.boot = {
|
||||
kernelModules = lists.optional cfg.hardened "tcp_bbr";
|
||||
kernel.sysctl = mkIf cfg.hardened {
|
||||
"kernel.sysrq" = 0; # Disable magic SysRq key
|
||||
# Ignore ICMP broadcasts to avoid participating in Smurf attacks
|
||||
"net.ipv4.icmp_echo_ignore_broadcasts" = 1;
|
||||
# Ignore bad ICMP errors
|
||||
"net.ipv4.icmp_ignore_bogus_error_responses" = 1;
|
||||
# SYN flood protection
|
||||
"net.ipv4.tcp_syncookies" = 1;
|
||||
# Do not accept ICMP redirects (prevent MITM attacks)
|
||||
"net.ipv4.conf.all.accept_redirects" = 0;
|
||||
"net.ipv4.conf.default_accept_redirects" = 0;
|
||||
"net.ipv4.conf.all.secure_redirects" = 0;
|
||||
"net.ipv4.conf.default.secure_redirects" = 0;
|
||||
"net.ipv6.conf.all.accept_redirects" = 0;
|
||||
"net.ipv6.conf.default.accept_redirects" = 0;
|
||||
# Do not send ICMP redirects (we are not a router)
|
||||
"net.ipv4.conf.all.send_redirects" = 0;
|
||||
# Do not accept IP source route packets (we are not a router)
|
||||
"net.ipv4.conf.all.accept_source_route" = 0;
|
||||
"net.ipv6.conf.all.accept_source_route" = 0;
|
||||
# Protect against tcp time-wait assassination hazards
|
||||
"net.ipv4.tcp_rfc1337" = 1;
|
||||
# Latency reduction
|
||||
"net.ipv4.tcp_fastopen" = 3;
|
||||
# Bufferfloat mitigations
|
||||
"net.ipv4.tcp_congestion_control" = "bbr";
|
||||
"net.core.default_qdisc" = "cake";
|
||||
};
|
||||
boot = {
|
||||
kernelModules = ["tcp_bbr"];
|
||||
kernel.sysctl = {
|
||||
"kernel.sysrq" = 0;
|
||||
"net.ipv4.icmp_echo_ignore_broadcasts" = 1;
|
||||
"net.ipv4.icmp_ignore_bogus_error_responses" = 1;
|
||||
"net.ipv4.conf.all.accept_redirects" = 0;
|
||||
"net.ipv4.conf.default_accept_redirects" = 0;
|
||||
"net.ipv4.conf.all.secure_redirects" = 0;
|
||||
"net.ipv4.conf.default.secure_redirects" = 0;
|
||||
"net.ipv6.conf.all.accept_redirects" = 0;
|
||||
"net.ipv6.conf.default.accept_redirects" = 0;
|
||||
"net.ipv4.conf.all.send_redirects" = 0;
|
||||
"net.ipv4.conf.all.accept_source_route" = 0;
|
||||
"net.ipv6.conf.all.accept_source_route" = 0;
|
||||
"net.ipv4.tcp_syncookies" = 1;
|
||||
"net.ipv4.tcp_rfc1337" = 1;
|
||||
"net.ipv4.tcp_congestion_control" = "bbr";
|
||||
"net.core.default_qdisc" = "cake";
|
||||
"net.ipv4.tcp_fastopen" = 3;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
#+title: Kernel Hardening
|
||||
#+setupfile: ../headers
|
||||
|
||||
* Kernel Hardening
|
||||
Some of my machines are exposed to the Internet, and therefore get
|
||||
their kernel hardened. First, let me declare the Nix file’s skeleton,
|
||||
with the =nixos.hardened= module.
|
||||
|
||||
#+begin_src nix :tangle yes
|
||||
{
|
||||
flake.modules.nixos.hardened = {
|
||||
boot = {
|
||||
<<kernel-modules>>
|
||||
<<kernel-options>>
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Kernel Modules
|
||||
The very first thing to do is to load the =tcp_bbr= kernel module. It
|
||||
increases the connection speed of the system with a better congestion
|
||||
control. It is particularly interesting for my servers, as they may
|
||||
have to deal with high traffic if a crawler ever decides to explore
|
||||
all webpages offered by some websites I host. See [[https://www.cyberciti.biz/cloud-computing/increase-your-linux-server-internet-speed-with-tcp-bbr-congestion-control/][this article]] by
|
||||
Nixcraft for more details.
|
||||
#+name: kernel-modules
|
||||
#+begin_src nix
|
||||
kernelModules = ["tcp_bbr"];
|
||||
#+end_src
|
||||
|
||||
** Kernel Options
|
||||
Next are a series of kernel options.
|
||||
#+name: kernel-options
|
||||
#+begin_src nix
|
||||
kernel.sysctl = {
|
||||
<<sysrq-key>>
|
||||
<<icmp>>
|
||||
<<icmp-no-accept-redirects>>
|
||||
<<icmp-no-send-redirects>>
|
||||
<<ip-source-route-packets>>
|
||||
<<syn>>
|
||||
<<tcp-time-wait>>
|
||||
<<bufferfloat>>
|
||||
<<latency>>
|
||||
};
|
||||
#+end_src
|
||||
|
||||
First, we’ll disable the magic SysRq key. Not that I expect anyone to
|
||||
have physical access to my servers, but it is a really powerful tool
|
||||
that I’d rather have off.
|
||||
#+name: sysrq-key
|
||||
#+begin_src nix
|
||||
"kernel.sysrq" = 0;
|
||||
#+end_src
|
||||
|
||||
Next, we’ll ignore ICMP broadcasts to avoid participating in Smurf
|
||||
attacks, and we’ll also ignore ICMP errors.
|
||||
#+name: icmp
|
||||
#+begin_src nix
|
||||
"net.ipv4.icmp_echo_ignore_broadcasts" = 1;
|
||||
"net.ipv4.icmp_ignore_bogus_error_responses" = 1;
|
||||
#+end_src
|
||||
|
||||
Speaking of ICMP, we won’t accept ICMP redirects to prevent some MITM
|
||||
attacks.
|
||||
#+name: icmp-no-accept-redirects
|
||||
#+begin_src nix
|
||||
"net.ipv4.conf.all.accept_redirects" = 0;
|
||||
"net.ipv4.conf.default_accept_redirects" = 0;
|
||||
"net.ipv4.conf.all.secure_redirects" = 0;
|
||||
"net.ipv4.conf.default.secure_redirects" = 0;
|
||||
"net.ipv6.conf.all.accept_redirects" = 0;
|
||||
"net.ipv6.conf.default.accept_redirects" = 0;
|
||||
#+end_src
|
||||
|
||||
And we won’t send ICMP redirects (we’re not a router).
|
||||
#+name: icmp-no-send-redirects
|
||||
#+begin_src nix
|
||||
"net.ipv4.conf.all.send_redirects" = 0;
|
||||
#+end_src
|
||||
|
||||
We’re stil not a router, so we’ll refuse IP source route packets, both
|
||||
on IPV4 and IPV6.
|
||||
#+name: ip-source-route-packets
|
||||
#+begin_src nix
|
||||
"net.ipv4.conf.all.accept_source_route" = 0;
|
||||
"net.ipv6.conf.all.accept_source_route" = 0;
|
||||
#+end_src
|
||||
|
||||
Now, let’s get some SYN flood protection.
|
||||
#+name: syn
|
||||
#+begin_src nix
|
||||
"net.ipv4.tcp_syncookies" = 1;
|
||||
#+end_src
|
||||
|
||||
And protection against TCP time-wait assassination hazards.
|
||||
#+name: tcp-time-wait
|
||||
#+begin_src nix
|
||||
"net.ipv4.tcp_rfc1337" = 1;
|
||||
#+end_src
|
||||
|
||||
We will also mitigate bufferfloat, including with BBR (hey, we enabled that above!)
|
||||
#+name: bufferfloat
|
||||
#+begin_src nix
|
||||
"net.ipv4.tcp_congestion_control" = "bbr";
|
||||
"net.core.default_qdisc" = "cake";
|
||||
#+end_src
|
||||
|
||||
And lastly, we’ll reduce latency on IPV4.
|
||||
#+name: latency
|
||||
#+begin_src nix
|
||||
"net.ipv4.tcp_fastopen" = 3;
|
||||
#+end_src
|
||||
|
||||
And we should be good to go!
|
||||
+2
-11
@@ -1,6 +1,4 @@
|
||||
{config, ...}: let
|
||||
flakeModules = config.flake.modules;
|
||||
in {
|
||||
{
|
||||
flake.modules.nixos.kernel = {
|
||||
pkgs,
|
||||
config,
|
||||
@@ -10,8 +8,6 @@ in {
|
||||
with lib; let
|
||||
cfg = config.mySystem.boot.kernel;
|
||||
in {
|
||||
imports = [flakeModules.nixos.amdgpu];
|
||||
|
||||
options.mySystem.boot.kernel = {
|
||||
package = mkOption {
|
||||
type = types.raw;
|
||||
@@ -35,13 +31,8 @@ in {
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config.boot = {
|
||||
initrd.kernelModules = lib.lists.singleton (
|
||||
if config.mySystem.hardware.amdgpu.enable
|
||||
then "amdgpu"
|
||||
else "i915"
|
||||
);
|
||||
initrd.kernelModules = ["i915"];
|
||||
extraModprobeConfig =
|
||||
strings.concatLines
|
||||
([cfg.extraModprobeConfig]
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
#+title: Kernel Configuration
|
||||
#+setupfile: ../headers
|
||||
|
||||
* Kernel Configuration
|
||||
This module centralises everything related to the kernel: which
|
||||
package to boot, which extra modules to load, which KVM module the
|
||||
CPU needs, and a couple of modprobe quirks for specific devices.
|
||||
Here’s the skeleton of the =nixos.kernel= module.
|
||||
#+begin_src nix :tangle yes
|
||||
{
|
||||
flake.modules.nixos.kernel = {
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.mySystem.boot.kernel;
|
||||
in {
|
||||
<<options>>
|
||||
<<config>>
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Declaring the Options
|
||||
#+name: options
|
||||
#+begin_src nix
|
||||
options.mySystem.boot.kernel = {
|
||||
<<opt-package>>
|
||||
<<opt-modules>>
|
||||
<<opt-cpu-vendor>>
|
||||
<<opt-v4l2loopback>>
|
||||
<<opt-extra-modprobe>>
|
||||
};
|
||||
#+end_src
|
||||
|
||||
*** Kernel Package
|
||||
=package= picks which kernel to boot. I default to the Zen kernel for
|
||||
its desktop-tuned scheduler, but a host can override it with a
|
||||
hardened or hardware-specific kernel instead.
|
||||
#+name: opt-package
|
||||
#+begin_src nix
|
||||
package = mkOption {
|
||||
type = types.raw;
|
||||
default = pkgs.linuxPackages_zen;
|
||||
};
|
||||
#+end_src
|
||||
|
||||
*** Extra Kernel Modules
|
||||
=modules= lists any extra kernel modules a host needs beyond the ones
|
||||
this module already adds on its own.
|
||||
#+name: opt-modules
|
||||
#+begin_src nix
|
||||
modules = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
#+end_src
|
||||
|
||||
*** CPU Vendor
|
||||
=cpuVendor= tells the module which KVM module to load, since Intel and
|
||||
AMD CPUs each need their own.
|
||||
#+name: opt-cpu-vendor
|
||||
#+begin_src nix
|
||||
cpuVendor = mkOption {
|
||||
description = "Intel or AMD?";
|
||||
type = types.enum ["intel" "amd"];
|
||||
default = "amd";
|
||||
};
|
||||
#+end_src
|
||||
|
||||
*** Virtual Webcam
|
||||
=v4l2loopback.enable= turns on a virtual video device. I feed it a
|
||||
video source, and OBS Studio picks it up as if it were a webcam.
|
||||
#+name: opt-v4l2loopback
|
||||
#+begin_src nix
|
||||
v4l2loopback.enable = mkEnableOption "Enables v4l2loopback kernel module";
|
||||
#+end_src
|
||||
|
||||
*** Extra Modprobe Configuration
|
||||
=extraModprobeConfig= lets a host inject raw =modprobe.d= lines. The
|
||||
example below fixes a USB sound card that otherwise misconfigures
|
||||
itself on boot.
|
||||
#+name: opt-extra-modprobe
|
||||
#+begin_src nix
|
||||
extraModprobeConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
options snd_usb_audio vid=0x1235 pid=0x8212 device_setup=1
|
||||
'';
|
||||
};
|
||||
#+end_src
|
||||
|
||||
** Wiring It All Up
|
||||
#+name: config
|
||||
#+begin_src nix
|
||||
config.boot = {
|
||||
<<initrd-driver>>
|
||||
<<extra-modprobe-lines>>
|
||||
<<kernel-packages-and-modules>>
|
||||
};
|
||||
#+end_src
|
||||
|
||||
*** Choosing the Initrd Driver
|
||||
Most of my machines have Intel graphics, so this module loads =i915=
|
||||
early, in the initrd, to keep the Plymouth splash screen from flashing
|
||||
or glitching before the proper driver takes over. Machines with an AMD
|
||||
GPU instead load =amdgpu= early; the [[file:../hardware/amdgpu.org][AMD GPU module]] handles that
|
||||
itself, so this module doesn’t need to know or care which GPU a host
|
||||
actually has.
|
||||
#+name: initrd-driver
|
||||
#+begin_src nix
|
||||
initrd.kernelModules = ["i915"];
|
||||
#+end_src
|
||||
|
||||
*** Assembling Modprobe Configuration
|
||||
This concatenates whatever a host set through =cfg.extraModprobeConfig=
|
||||
with the v4l2loopback quirk line whenever =v4l2loopback.enable= is on.
|
||||
#+name: extra-modprobe-lines
|
||||
#+begin_src nix
|
||||
extraModprobeConfig =
|
||||
strings.concatLines
|
||||
([cfg.extraModprobeConfig]
|
||||
++ lists.optional cfg.v4l2loopback.enable ''options v4l2loopback exclusive_caps=1 devices=1 video_nr=0 card_label="OBS Studio"'');
|
||||
#+end_src
|
||||
|
||||
*** Kernel Package and Extra Modules
|
||||
Finally, =kernelPackages= and =kernelModules= wire the chosen package
|
||||
and modules through, appending the vendor-specific KVM module.
|
||||
#+name: kernel-packages-and-modules
|
||||
#+begin_src nix
|
||||
kernelPackages = cfg.package;
|
||||
kernelModules = cfg.modules ++ ["kvm-${cfg.cpuVendor}"];
|
||||
#+end_src
|
||||
+16
-30
@@ -7,39 +7,25 @@
|
||||
with lib; let
|
||||
cfg = config.mySystem.boot;
|
||||
in {
|
||||
options.mySystem.boot = {
|
||||
systemd-boot = mkOption {
|
||||
type = types.bool;
|
||||
default = !cfg.grub.enable;
|
||||
description = "Does the system use systemd-boot?";
|
||||
};
|
||||
grub = {
|
||||
enable = mkEnableOption "Does the system use GRUB? (Disables systemd-boot)";
|
||||
device = mkOption {
|
||||
type = types.path;
|
||||
description = "The GRUB device";
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
zfs = {
|
||||
enable = mkEnableOption "Enables ZFS";
|
||||
pools = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
options.mySystem.boot.systemd-boot = mkOption {
|
||||
type = types.bool;
|
||||
default = !cfg.grub.enable;
|
||||
description = "Does the system use systemd-boot?";
|
||||
};
|
||||
options.mySystem.boot.grub = {
|
||||
enable = mkEnableOption "Does the system use GRUB? (Disables systemd-boot)";
|
||||
device = mkOption {
|
||||
type = types.path;
|
||||
description = "The GRUB device";
|
||||
};
|
||||
};
|
||||
|
||||
config.boot = {
|
||||
loader = {
|
||||
systemd-boot.enable = cfg.systemd-boot;
|
||||
efi.canTouchEfiVariables = cfg.systemd-boot;
|
||||
grub = mkIf cfg.grub.enable {
|
||||
inherit (cfg.grub) enable device;
|
||||
};
|
||||
};
|
||||
supportedFilesystems = mkIf cfg.zfs.enable ["zfs"];
|
||||
zfs.extraPools = mkIf cfg.zfs.enable cfg.zfs.pools;
|
||||
config.boot.loader = {
|
||||
systemd-boot.enable = cfg.systemd-boot;
|
||||
efi.canTouchEfiVariables = cfg.systemd-boot;
|
||||
};
|
||||
config.boot.loader.grub = mkIf cfg.grub.enable {
|
||||
inherit (cfg.grub) enable device;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#+title: Bootloaders and Filesystems
|
||||
#+setupfile: ../headers
|
||||
|
||||
* Bootloaders and Filesystems
|
||||
This page sets up the bootloader of my machines. Whilst I generally
|
||||
prefer to use [[https://systemd.io/BOOT/][systemd-boot]], some of my VPS use GRUB. All that gets
|
||||
exposed with my module =nixos.loader=.
|
||||
|
||||
#+begin_src nix :tangle yes
|
||||
{
|
||||
flake.modules.nixos.loader = {
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.mySystem.boot;
|
||||
in {
|
||||
<<systemd-boot-options>>
|
||||
<<grub-options>>
|
||||
|
||||
<<systemd-boot-config>>
|
||||
<<grub-config>>
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
By default, I want to use systemd-boot on my machines, but I need it
|
||||
to be disabled whenever I use something else. For now, this “something
|
||||
else” is only GRUB, but I’m not excluding using something else on yet
|
||||
another machine such as [[https://www.rodsbooks.com/refind/][rEFInd]]. To ensure a single source of truth
|
||||
regarding whether systemd-boot is to be used, I have an option for
|
||||
that.
|
||||
#+name: systemd-boot-options
|
||||
#+begin_src nix
|
||||
options.mySystem.boot.systemd-boot = mkOption {
|
||||
type = types.bool;
|
||||
default = !cfg.grub.enable;
|
||||
description = "Does the system use systemd-boot?";
|
||||
};
|
||||
#+end_src
|
||||
|
||||
I can now set some options depending on that, such as whether to
|
||||
enable systemd-boot itself (duh), and whether the installation process
|
||||
can touch my EFI variables.
|
||||
#+name: systemd-boot-config
|
||||
#+begin_src nix
|
||||
config.boot.loader = {
|
||||
systemd-boot.enable = cfg.systemd-boot;
|
||||
efi.canTouchEfiVariables = cfg.systemd-boot;
|
||||
};
|
||||
#+end_src
|
||||
|
||||
But, I have a VPS that requires me to use GRUB. For this, I also have
|
||||
an option to enable it.
|
||||
#+name: grub-options
|
||||
#+begin_src nix
|
||||
options.mySystem.boot.grub = {
|
||||
enable = mkEnableOption "Does the system use GRUB? (Disables systemd-boot)";
|
||||
device = mkOption {
|
||||
type = types.path;
|
||||
description = "The GRUB device";
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
|
||||
I can no pass these options to the boot configuration of my machine.
|
||||
#+name: grub-config
|
||||
#+begin_src nix
|
||||
config.boot.loader.grub = mkIf cfg.grub.enable {
|
||||
inherit (cfg.grub) enable device;
|
||||
};
|
||||
#+end_src
|
||||
+20
-30
@@ -1,35 +1,25 @@
|
||||
{
|
||||
flake.modules.nixos.plymouth = {
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.mySystem.boot.plymouth;
|
||||
in {
|
||||
options.mySystem.boot.plymouth.enable = mkEnableOption "Enables Plymouth at system boot";
|
||||
config.boot = mkIf cfg.enable {
|
||||
plymouth = {
|
||||
inherit (cfg) enable;
|
||||
theme = "circle_hud";
|
||||
themePackages = with pkgs; [
|
||||
(adi1090x-plymouth-themes.override {
|
||||
selected_themes = ["circle_hud"];
|
||||
})
|
||||
];
|
||||
};
|
||||
consoleLogLevel = 3;
|
||||
initrd.verbose = false;
|
||||
kernelParams = [
|
||||
"quiet"
|
||||
"splash"
|
||||
"boot.shell_on_fail"
|
||||
"udev.log_priority=3"
|
||||
"rd.systemd.show_status=auto"
|
||||
flake.modules.nixos.plymouth = {pkgs, ...}: {
|
||||
boot = {
|
||||
plymouth = {
|
||||
enable = true;
|
||||
theme = "circle_hud";
|
||||
themePackages = with pkgs; [
|
||||
(adi1090x-plymouth-themes.override {
|
||||
selected_themes = ["circle_hud"];
|
||||
})
|
||||
];
|
||||
# Loader appears only if a key is pressed
|
||||
loader.timeout = 0;
|
||||
};
|
||||
kernelParams = [
|
||||
"quiet"
|
||||
"splash"
|
||||
"boot.shell_on_fail"
|
||||
"udev.log_level=3"
|
||||
"rd.systemd.show_status=auto"
|
||||
];
|
||||
consoleLogLevel = 3;
|
||||
initrd.verbose = false;
|
||||
loader.timeout = 0;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#+title: Plymouth
|
||||
#+setupfile: ../headers
|
||||
|
||||
* Plymouth
|
||||
Plymouth is a utility which shows an animation at startup or when
|
||||
powering off a device, instead of showing only terminal things. My
|
||||
Plymouth settings are set in the =nixos.plymouth= module.
|
||||
|
||||
#+begin_src nix :tangle yes
|
||||
{
|
||||
flake.modules.nixos.plymouth = {pkgs, ...}: {
|
||||
boot = {
|
||||
<<plymouth>>
|
||||
<<kernel-parameters>>
|
||||
<<quiet-console>>
|
||||
<<no-menu>>
|
||||
};
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
** Quieting Down the Console
|
||||
First, I need to set a few kernel parameters to make displaying
|
||||
Plymouth possible:
|
||||
#+name: kernel-parameters-list
|
||||
- =quiet= :: silences the logs in the terminal
|
||||
- =splash= :: show the splash screen (in our case, Plymouth)
|
||||
- =boot.shell_on_fail= :: sets =allowShell=1=, which permits the =fail()=
|
||||
handler to drop an interactive rescue shell if stage-1 boot fails
|
||||
- =udev.log_level=3= :: sets udev’s log level to =err=
|
||||
- =rd.systemd.show_status=auto= :: suppress systemd status messages in
|
||||
initrd unless boot is significantly delayed
|
||||
|
||||
#+name: kernel-params
|
||||
#+begin_src emacs-lisp :var params=kernel-parameters-list :cache yes
|
||||
(mapconcat (lambda (param)
|
||||
(format "\"%s\""
|
||||
(s-chop-suffix "=" (s-chop-prefix "=" (car (s-split " ::" param))))))
|
||||
params
|
||||
"\n")
|
||||
#+end_src
|
||||
|
||||
#+RESULTS[7a824c095f2934792b4a3749e56091a8603aaacf]: kernel-params
|
||||
: "quiet"
|
||||
: "splash"
|
||||
: "boot.shell_on_fail"
|
||||
: "udev.log_level=3"
|
||||
: "rd.systemd.show_status=auto"
|
||||
|
||||
This translates into:
|
||||
#+name: kernel-parameters
|
||||
#+begin_src nix :noweb yes
|
||||
kernelParams = [
|
||||
<<kernel-params()>>
|
||||
];
|
||||
#+end_src
|
||||
|
||||
To further decrease the verbosity of the booting screen, we can
|
||||
deactivate initrd’s verbosity and lower the console’s log level to
|
||||
=err=.
|
||||
#+name: quiet-console
|
||||
#+begin_src nix
|
||||
consoleLogLevel = 3;
|
||||
initrd.verbose = false;
|
||||
#+end_src
|
||||
|
||||
And we’ll show Plymouth immediately, skipping the bootloader’s menu.
|
||||
We can hold a key to force displaying the menu, though.
|
||||
#+name: no-menu
|
||||
#+begin_src nix
|
||||
loader.timeout = 0;
|
||||
#+end_src
|
||||
|
||||
|
||||
** Configuring Plymouth
|
||||
Now, we can configure Plymouth proper.
|
||||
#+name: plymouth
|
||||
#+begin_src nix
|
||||
plymouth = {
|
||||
enable = true;
|
||||
<<plymouth-theme>>
|
||||
};
|
||||
#+end_src
|
||||
|
||||
The only significant configuration I want to change in Plymouth is the
|
||||
animation. I really like how it looks. You can find a preview of it in
|
||||
[[https://github.com/adi1090x/plymouth-themes#previews][adi1090x's repository]], under the first pack. For this, I need to set
|
||||
a theme package and the theme name.
|
||||
#+name: plymouth-theme
|
||||
#+begin_src nix
|
||||
theme = "circle_hud";
|
||||
themePackages = with pkgs; [
|
||||
(adi1090x-plymouth-themes.override {
|
||||
selected_themes = ["circle_hud"];
|
||||
})
|
||||
];
|
||||
#+end_src
|
||||
|
||||
And we’re done!
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
flake.modules.nixos.zfs = {
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.mySystem.boot;
|
||||
in {
|
||||
options.mySystem.boot.zfs = {
|
||||
pools = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
forceImportRoot = mkEnableOption "Force-import the ZFS root pool at boot, even if it looks already imported elsewhere";
|
||||
};
|
||||
config.boot.supportedFilesystems = ["zfs"];
|
||||
config.boot.zfs.extraPools = cfg.zfs.pools;
|
||||
config.boot.zfs.forceImportRoot = cfg.zfs.forceImportRoot;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#+title: ZFS Support
|
||||
#+setupfile: ../headers
|
||||
|
||||
* ZFS Support
|
||||
Enabling ZFS is quite straightforward on my machines. In my module
|
||||
=nixos.zfs=, I expose two options: which ZFS pools to import, and
|
||||
whether to force-import the root pool. But first, here’s the skeleton
|
||||
of my module.
|
||||
|
||||
#+begin_src nix :tangle yes
|
||||
{
|
||||
flake.modules.nixos.zfs = {
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.mySystem.boot;
|
||||
in {
|
||||
<<options>>
|
||||
<<enable>>
|
||||
<<pools>>
|
||||
<<force-import-root>>
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
The main option is the list of pools, which I pass directly to the
|
||||
standard NixOS configuration.
|
||||
#+name: options
|
||||
#+begin_src nix
|
||||
options.mySystem.boot.zfs = {
|
||||
pools = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
forceImportRoot = mkEnableOption "Force-import the ZFS root pool at boot, even if it looks already imported elsewhere";
|
||||
};
|
||||
#+end_src
|
||||
|
||||
Now, I can enable ZFS on the system importing the current module.
|
||||
#+name: enable
|
||||
#+begin_src nix
|
||||
config.boot.supportedFilesystems = ["zfs"];
|
||||
#+end_src
|
||||
|
||||
And lastly, passing the list of pools to the standard NixOS option is
|
||||
quite simple.
|
||||
#+name: pools
|
||||
#+begin_src nix
|
||||
config.boot.zfs.extraPools = cfg.zfs.pools;
|
||||
#+end_src
|
||||
|
||||
Force-importing the root pool can paper over a stale or mismatched
|
||||
host ID, but it also risks mounting a pool that’s already imported
|
||||
elsewhere and corrupting it, so NixOS is moving to disable it by
|
||||
default. I’d rather keep that safety and only turn it back on for the
|
||||
rare host (or the rare boot) that actually needs it.
|
||||
#+name: force-import-root
|
||||
#+begin_src nix
|
||||
config.boot.zfs.forceImportRoot = cfg.zfs.forceImportRoot;
|
||||
#+end_src
|
||||
Reference in New Issue
Block a user