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:
+17
@@ -0,0 +1,17 @@
|
|||||||
|
* Licensing
|
||||||
|
The source code you can find in various programming languages in this
|
||||||
|
repository including, but not limited to, Javascript and CSS source
|
||||||
|
code is under the [[https://www.gnu.org/licenses/agpl-3.0.html][AGPL-3.0]] licence.
|
||||||
|
|
||||||
|
The creative work contained in [[https://labs.phundrak.com/phundrak/langue-phundrak-com][the main code repository]], on my [[https://github.com/Phundrak/langue-phundrak-fr/][Github
|
||||||
|
mirror]], and on my website [[https://langue.phundrak.com][langue.phundrak.com]] is dual-licenced
|
||||||
|
between the [[https://www.gnu.org/licenses/#FDL][GNU Free Documentation License]] ([[file:fdl-1.3.md][legal code]]) for the text
|
||||||
|
and the /Creative Commons Attribution-NonCommercial-ShareAlike 4.0
|
||||||
|
International/ ([[https://creativecommons.org/licenses/by-nc-sa/4.0/][CC BY-NC-SA 4.0]], [[https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode][legal code]]) license.
|
||||||
|
|
||||||
|
Copies of all the mentionned licenses can be found in this code
|
||||||
|
repository.
|
||||||
|
|
||||||
|
If you wish to obtain a special license that is incompatible with the
|
||||||
|
current ones, please contact me at [[mailto:lucien@phundrak.com][lucien@phundrak.com]] so we can
|
||||||
|
discuss it.
|
||||||
Generated
+7
-6
@@ -35,11 +35,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787985728,
|
"lastModified": 1789186140,
|
||||||
"narHash": "sha256-qKYq/NmpxLKn2ZcxNUGx7PgVlmxW833xKZ3Hngvvnro=",
|
"narHash": "sha256-CEKrGzjO7Zk+BC0bsIySyu7q0vdy68V5MMq8YNKPpsk=",
|
||||||
"owner": "caelestia-dots",
|
"owner": "caelestia-dots",
|
||||||
"repo": "cli",
|
"repo": "cli",
|
||||||
"rev": "56f404c61dff30d698961780aefcf48bd4dd7b86",
|
"rev": "6b84ee5090ec50f36aa1a53990d57ab0013925a0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -58,15 +58,16 @@
|
|||||||
"quickshell": "quickshell"
|
"quickshell": "quickshell"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1788247772,
|
"lastModified": 1789736975,
|
||||||
"narHash": "sha256-KJtxaK9Ws9DimBKdrZFs3iHjUHF/V1WviJx5A2zk86c=",
|
"narHash": "sha256-PVYroXR/tuQdsWjp2XAqOhgY6dV2kN5nyzH4zha6ZPs=",
|
||||||
"owner": "caelestia-dots",
|
"owner": "caelestia-dots",
|
||||||
"repo": "shell",
|
"repo": "shell",
|
||||||
"rev": "065dac2957a1f31bd2d2f029cabb96f69921f72b",
|
"rev": "d999d4878ee4cec134168e60d913714566a8cfa6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "caelestia-dots",
|
"owner": "caelestia-dots",
|
||||||
|
"ref": "stable",
|
||||||
"repo": "shell",
|
"repo": "shell",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# DO-NOT-EDIT. This file was auto-generated using github:denful/flake-file.
|
# DO-NOT-EDIT. This file was auto-generated using github:denful/flake-file.
|
||||||
# Use `nix run .#write-flake` to regenerate it.
|
# Use `nix run .#write-flake` to regenerate it.
|
||||||
{
|
{
|
||||||
description = "NixOS and Home Manager configuration of phundrak";
|
description = "NixOS and Home Manager configuration of P'undrak";
|
||||||
|
|
||||||
outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules);
|
outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules);
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
caelestia-shell = {
|
caelestia-shell = {
|
||||||
url = "github:caelestia-dots/shell";
|
url = "github:caelestia-dots/shell?ref=stable";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
flake-file.url = "github:vic/flake-file";
|
flake-file.url = "github:vic/flake-file";
|
||||||
|
|||||||
@@ -1,43 +1,25 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.hardened = {
|
flake.modules.nixos.hardened = {
|
||||||
lib,
|
boot = {
|
||||||
config,
|
kernelModules = ["tcp_bbr"];
|
||||||
...
|
kernel.sysctl = {
|
||||||
}:
|
"kernel.sysrq" = 0;
|
||||||
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;
|
"net.ipv4.icmp_echo_ignore_broadcasts" = 1;
|
||||||
# Ignore bad ICMP errors
|
|
||||||
"net.ipv4.icmp_ignore_bogus_error_responses" = 1;
|
"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.all.accept_redirects" = 0;
|
||||||
"net.ipv4.conf.default_accept_redirects" = 0;
|
"net.ipv4.conf.default_accept_redirects" = 0;
|
||||||
"net.ipv4.conf.all.secure_redirects" = 0;
|
"net.ipv4.conf.all.secure_redirects" = 0;
|
||||||
"net.ipv4.conf.default.secure_redirects" = 0;
|
"net.ipv4.conf.default.secure_redirects" = 0;
|
||||||
"net.ipv6.conf.all.accept_redirects" = 0;
|
"net.ipv6.conf.all.accept_redirects" = 0;
|
||||||
"net.ipv6.conf.default.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;
|
"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.ipv4.conf.all.accept_source_route" = 0;
|
||||||
"net.ipv6.conf.all.accept_source_route" = 0;
|
"net.ipv6.conf.all.accept_source_route" = 0;
|
||||||
# Protect against tcp time-wait assassination hazards
|
"net.ipv4.tcp_syncookies" = 1;
|
||||||
"net.ipv4.tcp_rfc1337" = 1;
|
"net.ipv4.tcp_rfc1337" = 1;
|
||||||
# Latency reduction
|
|
||||||
"net.ipv4.tcp_fastopen" = 3;
|
|
||||||
# Bufferfloat mitigations
|
|
||||||
"net.ipv4.tcp_congestion_control" = "bbr";
|
"net.ipv4.tcp_congestion_control" = "bbr";
|
||||||
"net.core.default_qdisc" = "cake";
|
"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 = {
|
flake.modules.nixos.kernel = {
|
||||||
pkgs,
|
pkgs,
|
||||||
config,
|
config,
|
||||||
@@ -10,8 +8,6 @@ in {
|
|||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.mySystem.boot.kernel;
|
cfg = config.mySystem.boot.kernel;
|
||||||
in {
|
in {
|
||||||
imports = [flakeModules.nixos.amdgpu];
|
|
||||||
|
|
||||||
options.mySystem.boot.kernel = {
|
options.mySystem.boot.kernel = {
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.raw;
|
type = types.raw;
|
||||||
@@ -35,13 +31,8 @@ in {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config.boot = {
|
config.boot = {
|
||||||
initrd.kernelModules = lib.lists.singleton (
|
initrd.kernelModules = ["i915"];
|
||||||
if config.mySystem.hardware.amdgpu.enable
|
|
||||||
then "amdgpu"
|
|
||||||
else "i915"
|
|
||||||
);
|
|
||||||
extraModprobeConfig =
|
extraModprobeConfig =
|
||||||
strings.concatLines
|
strings.concatLines
|
||||||
([cfg.extraModprobeConfig]
|
([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
|
||||||
+5
-19
@@ -7,39 +7,25 @@
|
|||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.mySystem.boot;
|
cfg = config.mySystem.boot;
|
||||||
in {
|
in {
|
||||||
options.mySystem.boot = {
|
options.mySystem.boot.systemd-boot = mkOption {
|
||||||
systemd-boot = mkOption {
|
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = !cfg.grub.enable;
|
default = !cfg.grub.enable;
|
||||||
description = "Does the system use systemd-boot?";
|
description = "Does the system use systemd-boot?";
|
||||||
};
|
};
|
||||||
grub = {
|
options.mySystem.boot.grub = {
|
||||||
enable = mkEnableOption "Does the system use GRUB? (Disables systemd-boot)";
|
enable = mkEnableOption "Does the system use GRUB? (Disables systemd-boot)";
|
||||||
device = mkOption {
|
device = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
description = "The GRUB device";
|
description = "The GRUB device";
|
||||||
default = "";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
zfs = {
|
|
||||||
enable = mkEnableOption "Enables ZFS";
|
|
||||||
pools = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config.boot = {
|
config.boot.loader = {
|
||||||
loader = {
|
|
||||||
systemd-boot.enable = cfg.systemd-boot;
|
systemd-boot.enable = cfg.systemd-boot;
|
||||||
efi.canTouchEfiVariables = cfg.systemd-boot;
|
efi.canTouchEfiVariables = cfg.systemd-boot;
|
||||||
grub = mkIf cfg.grub.enable {
|
};
|
||||||
|
config.boot.loader.grub = mkIf cfg.grub.enable {
|
||||||
inherit (cfg.grub) enable device;
|
inherit (cfg.grub) enable device;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
supportedFilesystems = mkIf cfg.zfs.enable ["zfs"];
|
|
||||||
zfs.extraPools = mkIf cfg.zfs.enable cfg.zfs.pools;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,17 +1,8 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.plymouth = {
|
flake.modules.nixos.plymouth = {pkgs, ...}: {
|
||||||
pkgs,
|
boot = {
|
||||||
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 = {
|
plymouth = {
|
||||||
inherit (cfg) enable;
|
enable = true;
|
||||||
theme = "circle_hud";
|
theme = "circle_hud";
|
||||||
themePackages = with pkgs; [
|
themePackages = with pkgs; [
|
||||||
(adi1090x-plymouth-themes.override {
|
(adi1090x-plymouth-themes.override {
|
||||||
@@ -19,16 +10,15 @@
|
|||||||
})
|
})
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
consoleLogLevel = 3;
|
|
||||||
initrd.verbose = false;
|
|
||||||
kernelParams = [
|
kernelParams = [
|
||||||
"quiet"
|
"quiet"
|
||||||
"splash"
|
"splash"
|
||||||
"boot.shell_on_fail"
|
"boot.shell_on_fail"
|
||||||
"udev.log_priority=3"
|
"udev.log_level=3"
|
||||||
"rd.systemd.show_status=auto"
|
"rd.systemd.show_status=auto"
|
||||||
];
|
];
|
||||||
# Loader appears only if a key is pressed
|
consoleLogLevel = 3;
|
||||||
|
initrd.verbose = false;
|
||||||
loader.timeout = 0;
|
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
|
||||||
+7
-12
@@ -25,7 +25,6 @@
|
|||||||
inputs.nixpkgsUnstable.follows = "nixpkgsPinetab2Kernel";
|
inputs.nixpkgsUnstable.follows = "nixpkgsPinetab2Kernel";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systems = ["x86_64-linux" "aarch64-linux"];
|
systems = ["x86_64-linux" "aarch64-linux"];
|
||||||
|
|
||||||
flake.lib = {
|
flake.lib = {
|
||||||
@@ -37,7 +36,6 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
mkHome = system: userName: hostName: {
|
mkHome = system: userName: hostName: {
|
||||||
"${userName}@${hostName}" = inputs.home-manager.lib.homeManagerConfiguration {
|
"${userName}@${hostName}" = inputs.home-manager.lib.homeManagerConfiguration {
|
||||||
pkgs = inputs.nixpkgs.legacyPackages.${system};
|
pkgs = inputs.nixpkgs.legacyPackages.${system};
|
||||||
@@ -48,7 +46,6 @@
|
|||||||
modules = [config.flake.modules.homeManager."${userName}-${hostName}"];
|
modules = [config.flake.modules.homeManager."${userName}-${hostName}"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
mkPinetab = buildPlatform: variantModule: {
|
mkPinetab = buildPlatform: variantModule: {
|
||||||
pinetab2 = inputs.nixpkgs.lib.nixosSystem {
|
pinetab2 = inputs.nixpkgs.lib.nixosSystem {
|
||||||
system = "aarch64-linux";
|
system = "aarch64-linux";
|
||||||
@@ -72,24 +69,22 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
flake.nixosConfigurations = lib.mkMerge [
|
flake.nixosConfigurations = lib.mkMerge [
|
||||||
(config.flake.lib.mkNixos "x86_64-linux" "elcafe")
|
|
||||||
(config.flake.lib.mkNixos "x86_64-linux" "gampo")
|
|
||||||
(config.flake.lib.mkNixos "x86_64-linux" "marpa")
|
(config.flake.lib.mkNixos "x86_64-linux" "marpa")
|
||||||
(config.flake.lib.mkNixos "x86_64-linux" "NaroMk3")
|
(config.flake.lib.mkNixos "x86_64-linux" "gampo")
|
||||||
(config.flake.lib.mkNixos "x86_64-linux" "tilo")
|
(config.flake.lib.mkNixos "x86_64-linux" "tilo")
|
||||||
|
(config.flake.lib.mkNixos "x86_64-linux" "elcafe")
|
||||||
|
(config.flake.lib.mkNixos "x86_64-linux" "NaroMk3")
|
||||||
(config.flake.lib.mkPinetab "x86_64-linux" config.flake.modules.nixos.pinetab2-gnome)
|
(config.flake.lib.mkPinetab "x86_64-linux" config.flake.modules.nixos.pinetab2-gnome)
|
||||||
];
|
];
|
||||||
|
|
||||||
flake.homeConfigurations = lib.mkMerge [
|
flake.homeConfigurations = lib.mkMerge [
|
||||||
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "elcafe")
|
|
||||||
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "gampo")
|
|
||||||
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "marpa")
|
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "marpa")
|
||||||
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "NaroMk3")
|
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "gampo")
|
||||||
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "pinetab2")
|
|
||||||
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "tilo")
|
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "tilo")
|
||||||
|
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "elcafe")
|
||||||
(config.flake.lib.mkHome "x86_64-linux" "creug" "elcafe")
|
(config.flake.lib.mkHome "x86_64-linux" "creug" "elcafe")
|
||||||
|
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "NaroMk3")
|
||||||
|
(config.flake.lib.mkHome "aarch64-linux" "phundrak" "pinetab2")
|
||||||
];
|
];
|
||||||
|
|
||||||
perSystem = {
|
perSystem = {
|
||||||
pkgs,
|
pkgs,
|
||||||
system,
|
system,
|
||||||
|
|||||||
@@ -15,6 +15,12 @@
|
|||||||
example = "kde";
|
example = "kde";
|
||||||
description = "Which DE to enable";
|
description = "Which DE to enable";
|
||||||
};
|
};
|
||||||
|
videoDrivers = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
example = ["amdgpu"];
|
||||||
|
description = "Extra X11 video drivers to load";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
config.services = mkIf cfg.enable {
|
config.services = mkIf cfg.enable {
|
||||||
displayManager = {
|
displayManager = {
|
||||||
@@ -36,7 +42,7 @@
|
|||||||
|
|
||||||
xserver = {
|
xserver = {
|
||||||
inherit (cfg) enable;
|
inherit (cfg) enable;
|
||||||
videoDrivers = lists.optional config.mySystem.hardware.amdgpu.enable "amdgpu";
|
videoDrivers = cfg.videoDrivers;
|
||||||
xkb = {
|
xkb = {
|
||||||
layout = "fr";
|
layout = "fr";
|
||||||
variant = "bepo_afnor";
|
variant = "bepo_afnor";
|
||||||
|
|||||||
@@ -8,15 +8,12 @@
|
|||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.mySystem.dev.qemu;
|
cfg = config.mySystem.dev.qemu;
|
||||||
in {
|
in {
|
||||||
options.mySystem.dev.qemu = {
|
options.mySystem.dev.qemu.users = mkOption {
|
||||||
enable = mkEnableOption "Enable QEMU";
|
|
||||||
users = mkOption {
|
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = ["phundrak"];
|
default = ["phundrak"];
|
||||||
example = ["user1" "user2"];
|
example = ["user1" "user2"];
|
||||||
};
|
};
|
||||||
};
|
config = {
|
||||||
config = mkIf cfg.enable {
|
|
||||||
programs.virt-manager.enable = true;
|
programs.virt-manager.enable = true;
|
||||||
users.groups.libvirtd.members = cfg.users;
|
users.groups.libvirtd.members = cfg.users;
|
||||||
virtualisation = {
|
virtualisation = {
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#+title: QEMU
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* QEMU
|
||||||
|
On machines where I run virtual machines, I want =virt-manager=,
|
||||||
|
=libvirtd=, and a few supporting pieces set up together. Here’s the
|
||||||
|
skeleton of the =nixos.qemu= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.qemu = {
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib; let
|
||||||
|
cfg = config.mySystem.dev.qemu;
|
||||||
|
in {
|
||||||
|
<<options>>
|
||||||
|
config = {
|
||||||
|
<<virt-manager>>
|
||||||
|
<<libvirtd-group>>
|
||||||
|
<<virtualisation>>
|
||||||
|
<<packages>>
|
||||||
|
<<firmware-tmpfiles>>
|
||||||
|
<<binfmt>>
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Declaring the Options
|
||||||
|
=users= lists which users get added to the =libvirtd= group, so they can
|
||||||
|
manage VMs without needing root. By default, I add myself to this
|
||||||
|
group.
|
||||||
|
#+name: options
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.dev.qemu.users = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = ["phundrak"];
|
||||||
|
example = ["user1" "user2"];
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
This option is then passed onto the standard NixOS option.
|
||||||
|
#+name: libvirtd-group
|
||||||
|
#+begin_src nix
|
||||||
|
users.groups.libvirtd.members = cfg.users;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** virt-manager
|
||||||
|
This pulls in the GUI I actually use to create and manage VMs.
|
||||||
|
#+name: virt-manager
|
||||||
|
#+begin_src nix
|
||||||
|
programs.virt-manager.enable = true;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Virtualisation Backend
|
||||||
|
=libvirtd= is the daemon that actually runs and manages the VMs. SPICE
|
||||||
|
USB redirection lets me pass a USB device straight through to a guest
|
||||||
|
without unplugging it from the host first.
|
||||||
|
#+name: virtualisation
|
||||||
|
#+begin_src nix
|
||||||
|
virtualisation = {
|
||||||
|
libvirtd.enable = true;
|
||||||
|
spiceUSBRedirection.enable = true;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Extra Packages
|
||||||
|
Besides =qemu= itself, =quickemu= lets me spin up a VM from a template in
|
||||||
|
one command, and =swtpm= provides the software TPM that guests like
|
||||||
|
Windows 11 insist on.
|
||||||
|
#+name: packages
|
||||||
|
#+begin_src nix
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
qemu
|
||||||
|
quickemu
|
||||||
|
swtpm
|
||||||
|
];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Firmware Lookup Path
|
||||||
|
=virt-manager= and friends expect to find UEFI firmware images under
|
||||||
|
=/var/lib/qemu/firmware=, so I symlink QEMU’s own copy there instead of
|
||||||
|
making every tool aware of the Nix store path.
|
||||||
|
#+name: firmware-tmpfiles
|
||||||
|
#+begin_src nix
|
||||||
|
systemd.tmpfiles.rules = ["L+ /var/lib/qemu/firmware - - - - ${pkgs.qemu}/share/qemu/firmware"];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** ARM Emulation
|
||||||
|
This lets me run (and build) =aarch64-linux= binaries transparently
|
||||||
|
through QEMU’s user-mode emulation, which comes in handy when working
|
||||||
|
on the PineTab2 without needing actual ARM hardware on hand.
|
||||||
|
#+name: binfmt
|
||||||
|
#+begin_src nix
|
||||||
|
boot.binfmt.emulatedSystems = ["aarch64-linux"];
|
||||||
|
#+end_src
|
||||||
+16
-30
@@ -1,34 +1,22 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.amdgpu = {
|
flake.modules.nixos.amdgpu = {pkgs, ...}: {
|
||||||
pkgs,
|
hardware.graphics = {
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.mySystem.hardware.amdgpu;
|
|
||||||
in {
|
|
||||||
options.mySystem.hardware.amdgpu.enable = mkEnableOption "Enables an AMD GPU configuration";
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
hardware = {
|
|
||||||
graphics = {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
enable32Bit = true;
|
enable32Bit = true;
|
||||||
extraPackages = with pkgs; [
|
|
||||||
mesa # Mesa drivers for AMD GPUs
|
|
||||||
rocmPackages.clr # common language runtime for ROCm
|
|
||||||
rocmPackages.clr.icd # ROCm ICD for OpenCL
|
|
||||||
rocmPackages.rocblas # ROCm BLAS library
|
|
||||||
rocmPackages.hipblas #
|
|
||||||
rocmPackages.rpp # High-performance computer vision library
|
|
||||||
nvtopPackages.amd # GPU utilization monitoring
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
amdgpu = {
|
hardware.amdgpu = {
|
||||||
initrd.enable = true;
|
initrd.enable = true;
|
||||||
opencl.enable = true;
|
opencl.enable = true;
|
||||||
};
|
};
|
||||||
};
|
hardware.graphics.extraPackages = with pkgs; [
|
||||||
|
mesa
|
||||||
|
rocmPackages.clr
|
||||||
|
rocmPackages.clr.icd
|
||||||
|
rocmPackages.rocblas
|
||||||
|
rocmPackages.hipblas
|
||||||
|
rocmPackages.rpp
|
||||||
|
nvtopPackages.amd
|
||||||
|
];
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
clinfo
|
clinfo
|
||||||
amdgpu_top
|
amdgpu_top
|
||||||
@@ -53,12 +41,10 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
environment.variables = {
|
environment.variables = {
|
||||||
ROCM_PATH = "/opt/rocm"; # Set ROCm path
|
ROCM_PATH = "/opt/rocm";
|
||||||
HIP_VISIBLE_DEVICES = "1"; # Use only the eGPU (ID 1)
|
HIP_VISIBLE_DEVICES = "1";
|
||||||
ROCM_VISIBLE_DEVICES = "1"; # Optional: ROCm equivalent for visibility
|
ROCM_VISIBLE_DEVICES = "1";
|
||||||
# LD_LIBRARY_PATH = "/opt/rocm/lib"; # Add ROCm libraries
|
HSA_OVERRIDE_GFX_VERSION = "10.3.0";
|
||||||
HSA_OVERRIDE_GFX_VERSION = "10.3.0"; # Set GFX version override
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
#+title: AMD GPU support
|
||||||
|
#+setupfile: ../headers
|
||||||
|
#+property: header-args:emacs-lisp :lexical t :exports none :tangle no
|
||||||
|
|
||||||
|
* AMD GPU support
|
||||||
|
Only one of my machines has an AMD GPU, but it does require some
|
||||||
|
tweaking. First, here’s the skeleton of the =nixos.amdgpu= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.amdgpu = {pkgs, ...}: {
|
||||||
|
<<enable-graphics>>
|
||||||
|
<<enable-hardware>>
|
||||||
|
<<hardware-extra-packages>>
|
||||||
|
<<system-packages>>
|
||||||
|
<<lact>>
|
||||||
|
<<environment-variables>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Enable the Hardware
|
||||||
|
The first thing is to enable graphics in NixOS. We’ll enable 32-bit
|
||||||
|
support while we’re at it.
|
||||||
|
#+name: enable-graphics
|
||||||
|
#+begin_src nix
|
||||||
|
hardware.graphics = {
|
||||||
|
enable = true;
|
||||||
|
enable32Bit = true;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
We can now enable the hardware proper, including initrd and OpenCL
|
||||||
|
support for the GPU. =initrd.enable= already makes NixOS load =amdgpu= as
|
||||||
|
early as stage 1 on its own, which is why the kernel module (see
|
||||||
|
[[file:../boot/kernel.org][Kernel Configuration]]) doesn’t need to pick between =amdgpu= and =i915=
|
||||||
|
itself: it can simply default to =i915= and let this module handle its
|
||||||
|
own early loading.
|
||||||
|
#+name: enable-hardware
|
||||||
|
#+begin_src nix
|
||||||
|
hardware.amdgpu = {
|
||||||
|
initrd.enable = true;
|
||||||
|
opencl.enable = true;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Some software expect some packages to be installed by default, such as
|
||||||
|
rocblas or Hipblas. Here are these packages.
|
||||||
|
#+name: amd-packages
|
||||||
|
| Package Name | Description |
|
||||||
|
|----------------------+--------------------------------------------------------------------|
|
||||||
|
| =mesa= | Mesa drivers for AMD GPUs |
|
||||||
|
| =rocmPackages.clr= | Common Language Runtime for ROCm |
|
||||||
|
| =rocmPackages.clr.icd= | ROCm ICD for OpenCL |
|
||||||
|
| =rocmPackages.rocblas= | ROCm BLAS library |
|
||||||
|
| =rocmPackages.hipblas= | HIP BLAS marshalling library (CUDA-compatible interface to rocBLAS) |
|
||||||
|
| =rocmPackages.rpp= | High-performance computer vision library |
|
||||||
|
| =nvtopPackages.amd= | Just for me, GPU utilisation monitoring |
|
||||||
|
|
||||||
|
#+name: extra-hardware-packages
|
||||||
|
#+begin_src emacs-lisp :var packages=amd-packages :cache yes
|
||||||
|
(mapconcat (lambda (package) (s-chop-prefix "=" (s-chop-suffix "=" package)))
|
||||||
|
(mapcar #'car packages)
|
||||||
|
"\n")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[28ba71596b4f184338e46c76c0ba1aa41899bba0]: extra-hardware-packages
|
||||||
|
: mesa
|
||||||
|
: rocmPackages.clr
|
||||||
|
: rocmPackages.clr.icd
|
||||||
|
: rocmPackages.rocblas
|
||||||
|
: rocmPackages.hipblas
|
||||||
|
: rocmPackages.rpp
|
||||||
|
: nvtopPackages.amd
|
||||||
|
|
||||||
|
#+name: hardware-extra-packages
|
||||||
|
#+begin_src nix
|
||||||
|
hardware.graphics.extraPackages = with pkgs; [
|
||||||
|
<<extra-hardware-packages()>>
|
||||||
|
];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Diagnostics and Monitoring
|
||||||
|
Beyond what’s needed by the driver stack itself, I also want a couple
|
||||||
|
of tools available on the command line to check on the GPU: =clinfo= to
|
||||||
|
inspect the available OpenCL platforms and devices, =amdgpu_top= for a
|
||||||
|
=btop=-like view of the AMD GPU’s activity, and =nvtop= (packaged for AMD
|
||||||
|
under =nvtopPackages.amd=) for a more familiar process-oriented monitor.
|
||||||
|
#+name: system-packages
|
||||||
|
#+begin_src nix
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
clinfo
|
||||||
|
amdgpu_top
|
||||||
|
nvtopPackages.amd
|
||||||
|
];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** LACT, the GPU Control Daemon
|
||||||
|
[[https://github.com/ilya-zlobintsev/LACT][LACT]] (Linux AMDGPU Control Application) lets me tweak fan curves,
|
||||||
|
power limits and clocks on the card, through a daemon (=lactd=) and a
|
||||||
|
GUI that talks to it. The package ships both a systemd service
|
||||||
|
definition and a udev rule, so all that’s left for me to do is install
|
||||||
|
the package and make sure the daemon is started.
|
||||||
|
|
||||||
|
I’m also consolidating the ROCm libraries under =/opt/rocm= via a
|
||||||
|
=tmpfiles= rule. Some tools out there still expect to find ROCm
|
||||||
|
installed at that standard filesystem location rather than resolved
|
||||||
|
through the Nix store, so I build a combined derivation of the ROCm
|
||||||
|
packages I need and symlink it into place.
|
||||||
|
#+name: lact
|
||||||
|
#+begin_src nix
|
||||||
|
systemd = {
|
||||||
|
packages = with pkgs; [lact];
|
||||||
|
services.lactd.wantedBy = ["multi-user.target"];
|
||||||
|
tmpfiles.rules = let
|
||||||
|
rocmEnv = pkgs.symlinkJoin {
|
||||||
|
name = "rocm-combined";
|
||||||
|
paths = with pkgs.rocmPackages; [
|
||||||
|
clr
|
||||||
|
clr.icd
|
||||||
|
rocblas
|
||||||
|
hipblas
|
||||||
|
rpp
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in [
|
||||||
|
"L+ /opt/rocm - - - - ${rocmEnv}"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Environment Variables
|
||||||
|
Finally, a handful of environment variables to point tools at that
|
||||||
|
=/opt/rocm= prefix and to steer ROCm/HIP towards the right GPU. This
|
||||||
|
machine exposes the AMD card as device ID =1= (the other device being an
|
||||||
|
iGPU), so I pin both =HIP_VISIBLE_DEVICES= and =ROCM_VISIBLE_DEVICES= to
|
||||||
|
it. The card also isn’t officially supported by ROCm, hence the
|
||||||
|
=HSA_OVERRIDE_GFX_VERSION= override, which tells ROCm to treat it as the
|
||||||
|
closest supported architecture instead of refusing to run.
|
||||||
|
#+name: environment-variables
|
||||||
|
#+begin_src nix
|
||||||
|
environment.variables = {
|
||||||
|
ROCM_PATH = "/opt/rocm";
|
||||||
|
HIP_VISIBLE_DEVICES = "1";
|
||||||
|
ROCM_VISIBLE_DEVICES = "1";
|
||||||
|
HSA_OVERRIDE_GFX_VERSION = "10.3.0";
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -1,16 +1,6 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.bluetooth = {
|
flake.modules.nixos.bluetooth = {
|
||||||
lib,
|
hardware.bluetooth.enable = true;
|
||||||
config,
|
services.blueman.enable = true;
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.mySystem.hardware.bluetooth;
|
|
||||||
in {
|
|
||||||
options.mySystem.hardware.bluetooth.enable = mkEnableOption "Enable bluetooth";
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
hardware.bluetooth.enable = cfg.enable;
|
|
||||||
services.blueman.enable = cfg.enable;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#+title: Bluetooth
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* Bluetooth
|
||||||
|
Not all of my machines have Bluetooth hardware worth turning on, so
|
||||||
|
this is a plain toggle rather than something applied unconditionally.
|
||||||
|
Here’s the skeleton of the =nixos.bluetooth= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.bluetooth = {
|
||||||
|
<<config>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Enabling Bluetooth
|
||||||
|
Turning the option on enables Bluetooth support at the kernel level
|
||||||
|
and installs =blueman=, a tray applet I use to pair and manage devices
|
||||||
|
without digging through a terminal.
|
||||||
|
#+name: config
|
||||||
|
#+begin_src nix
|
||||||
|
hardware.bluetooth.enable = true;
|
||||||
|
services.blueman.enable = true;
|
||||||
|
#+end_src
|
||||||
@@ -1,15 +1,5 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.fingerprint = {
|
flake.modules.nixos.fingerprint = {
|
||||||
lib,
|
hardware.facter.detected.fingerprint.enable = true;
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.mySystem.hardware.fingerprint;
|
|
||||||
in {
|
|
||||||
options.mySystem.hardware.fingerprint.enable = mkEnableOption "Enable fingerprint reader";
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
hardware.facter.detected.fingerprint.enable = cfg.enable;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#+title: Fingerprint Reader
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* Fingerprint Reader
|
||||||
|
My ThinkPad x220 has a fingerprint reader, so this is a plain toggle
|
||||||
|
rather than something applied unconditionally. Here’s the skeleton of
|
||||||
|
the =nixos.fingerprint= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.fingerprint = {
|
||||||
|
<<config>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Enabling the Reader
|
||||||
|
Rather than picking a driver myself, I let [[https://github.com/numtide/nixos-facter-modules][nixos-facter]] detect the
|
||||||
|
reader and wire up the matching driver automatically.
|
||||||
|
#+name: config
|
||||||
|
#+begin_src nix
|
||||||
|
hardware.facter.detected.fingerprint.enable = true;
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#+title: Firmware
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* Firmware
|
||||||
|
A small module to pull in the full firmware blob set, for machines
|
||||||
|
where I’d rather not chase down which specific firmware package a
|
||||||
|
piece of hardware needs. Here’s the =nixos.firmware= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.firmware = {lib, ...}: {
|
||||||
|
<<enable-all-firmware>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
=mkDefault= keeps this overridable, in case a host needs to turn it back
|
||||||
|
off or pin a narrower set of firmware packages itself.
|
||||||
|
#+name: enable-all-firmware
|
||||||
|
#+begin_src nix
|
||||||
|
hardware.enableAllFirmware = lib.mkDefault true;
|
||||||
|
#+end_src
|
||||||
@@ -1,14 +1,6 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.corne = {
|
flake.modules.nixos.corne = {
|
||||||
lib,
|
services.udev = {
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.mySystem.hardware.input.corne;
|
|
||||||
in {
|
|
||||||
options.mySystem.hardware.input.corne.allowHidAccess = mkEnableOption "Enable HID access to the corne keyboard";
|
|
||||||
config.services.udev = mkIf cfg.allowHidAccess {
|
|
||||||
extraRules = ''
|
extraRules = ''
|
||||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{serial}=="*vial:f64c2b3c*", MODE="0660", GROUP="users", TAG+="uaccess", TAG+="udev-acl"
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{serial}=="*vial:f64c2b3c*", MODE="0660", GROUP="users", TAG+="uaccess", TAG+="udev-acl"
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#+title: Corne Keyboard
|
||||||
|
#+setupfile: ../../headers
|
||||||
|
|
||||||
|
* Corne Keyboard
|
||||||
|
I use a Corne (=crkbd=), a small split ergonomic keyboard, flashed with
|
||||||
|
[[https://get.vial.today/][Vial]], a QMK-based firmware that lets me remap keys live from a GUI
|
||||||
|
instead of having to reflash the keyboard every time I want to tweak
|
||||||
|
my layout. Here’s the skeleton of the =nixos.corne= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.corne = {
|
||||||
|
<<udev-rule>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Granting HID Access
|
||||||
|
By default, the =hidraw= device nodes created for the keyboard are only
|
||||||
|
accessible to root, which means Vial can’t talk to it without running
|
||||||
|
as root too. Instead, I add a =udev= rule matching my keyboard’s Vial
|
||||||
|
identifier (the part after =vial:= is the keyboard’s unique unlock ID,
|
||||||
|
burned into its firmware) and grant the =users= group read/write access
|
||||||
|
to it, tagging it for =uaccess= / =udev-acl= so it’s also picked up by the
|
||||||
|
logged-in session’s ACLs.
|
||||||
|
#+name: udev-rule
|
||||||
|
#+begin_src nix
|
||||||
|
services.udev = {
|
||||||
|
extraRules = ''
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{serial}=="*vial:f64c2b3c*", MODE="0660", GROUP="users", TAG+="uaccess", TAG+="udev-acl"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
flake.modules.nixos.disable-ibm-trackpoint = {
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
ATTRS{name}=="*TPPS/2 IBM TrackPoint", ENV{ID_INPUT}="", ENV{ID_INPUT_MOUSE}="", ENV{ID_INPUT_POINTINGSTICK}=""
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#+title: Disable the IBM TrackPoint
|
||||||
|
#+setupfile: ../../headers
|
||||||
|
|
||||||
|
* Disable the IBM TrackPoint
|
||||||
|
My ThinkPads come with IBM’s TrackPoint, the little red nub sitting
|
||||||
|
between the =G=, =H= and =B= keys. I don’t want it active, though, it has a
|
||||||
|
drift and I cannot fix it unless I change my keyboard. Thus, this
|
||||||
|
module exposes a way to turn it off. Here’s the skeleton of the
|
||||||
|
=nixos.disable-ibm-trackpoint= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.disable-ibm-trackpoint = {
|
||||||
|
<<udev-rule>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Disabling the TrackPoint
|
||||||
|
The TrackPoint shows up to the input stack as a regular pointer
|
||||||
|
device, so to disable it I can’t simply blacklist a driver — libinput
|
||||||
|
and friends would still pick it up through =evdev=. Instead, I match it
|
||||||
|
by its device name and clear the =ID_INPUT=, =ID_INPUT_MOUSE= and
|
||||||
|
=ID_INPUT_POINTINGSTICK= udev properties on it, which tells the input
|
||||||
|
stack to simply ignore the device as a pointing device.
|
||||||
|
#+name: udev-rule
|
||||||
|
#+begin_src nix
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
ATTRS{name}=="*TPPS/2 IBM TrackPoint", ENV{ID_INPUT}="", ENV{ID_INPUT_MOUSE}="", ENV{ID_INPUT_POINTINGSTICK}=""
|
||||||
|
'';
|
||||||
|
#+end_src
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
flake.modules.nixos.ibm-trackpoint = {
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.mySystem.hardware.input.ibmTrackpoint;
|
|
||||||
in {
|
|
||||||
options.mySystem.hardware.input.ibmTrackpoint.disable = mkEnableOption "Disable IBM’s trackpoint on ThinkPad";
|
|
||||||
config.services.udev = mkIf cfg.disable {
|
|
||||||
extraRules = ''
|
|
||||||
ATTRS{name}=="*TPPS/2 IBM TrackPoint", ENV{ID_INPUT}="", ENV{ID_INPUT_MOUSE}="", ENV{ID_INPUT_POINTINGSTICK}=""
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,9 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.opentablet = {
|
flake.modules.nixos.opentablet = {
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.mySystem.hardware.input.opentablet;
|
|
||||||
in {
|
|
||||||
options.mySystem.hardware.input.opentablet.enable = mkEnableOption "Enables OpenTablet drivers";
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
hardware.opentabletdriver = {
|
hardware.opentabletdriver = {
|
||||||
inherit (cfg) enable;
|
enable = true;
|
||||||
daemon.enable = true;
|
daemon.enable = true;
|
||||||
};
|
};
|
||||||
boot.kernelModules = ["wacom"];
|
boot.kernelModules = ["wacom"];
|
||||||
};
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#+title: OpenTabletDriver
|
||||||
|
#+setupfile: ../../headers
|
||||||
|
|
||||||
|
* OpenTabletDriver
|
||||||
|
Some of my machines are hooked up to a graphics tablet, a Wacom
|
||||||
|
Bamboo, driven by [[https://opentabletdriver.net/][OpenTabletDriver]]. I remember buying it for 15€, what
|
||||||
|
a deal that was! Anyway, since most of my hosts don’t have a tablet
|
||||||
|
attached, this is exposed as a regular toggle rather than enabled
|
||||||
|
unconditionally. Here’s the skeleton of the =nixos.opentablet= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.opentablet = {
|
||||||
|
<<config>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Enabling the Driver
|
||||||
|
Enabling OpenTabletDriver proper is just a matter of turning on the
|
||||||
|
module and its daemon. I also need to explicitly load the =wacom=
|
||||||
|
kernel module, since my tablet (like most of them) identifies itself
|
||||||
|
as a Wacom device at the hardware level regardless of brand.
|
||||||
|
#+name: config
|
||||||
|
#+begin_src nix
|
||||||
|
hardware.opentabletdriver = {
|
||||||
|
enable = true;
|
||||||
|
daemon.enable = true;
|
||||||
|
};
|
||||||
|
boot.kernelModules = ["wacom"];
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#+title: Trackball
|
||||||
|
#+setupfile: ../../headers
|
||||||
|
|
||||||
|
* Trackball
|
||||||
|
I use a trackball on some of my machines, and I middle-click by
|
||||||
|
pressing the left and right buttons together rather than through a
|
||||||
|
dedicated button. That’s the only downside of the two trackballs I
|
||||||
|
own; otherwise, I can’t recommend one enough. Here’s the
|
||||||
|
=nixos.trackball= module enabling this behaviour.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.trackball = {
|
||||||
|
<<middle-emulation>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Enabling middle-click emulation is simple:
|
||||||
|
#+name: middle-emulation
|
||||||
|
#+begin_src nix
|
||||||
|
services.libinput.mouse.middleEmulation = true;
|
||||||
|
#+end_src
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.pinetab2 = {lib, ...}:
|
flake.modules.nixos.pinetab2 = {
|
||||||
with lib; {
|
|
||||||
options.mySystem.hardware.pinetab2.enable = mkEnableOption "Activate support for the PineTab2";
|
|
||||||
config = {
|
|
||||||
boot.kernelParams = ["console=tty0" "console=ttyS2,1500000n8" "rootwait" "root=LABEL=NIXOS_SD" "rw"];
|
boot.kernelParams = ["console=tty0" "console=ttyS2,1500000n8" "rootwait" "root=LABEL=NIXOS_SD" "rw"];
|
||||||
hardware.sensor.iio.enable = true;
|
hardware.sensor.iio.enable = true;
|
||||||
services.avahi = {
|
services.avahi = {
|
||||||
@@ -10,5 +7,4 @@
|
|||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#+title: PineTab2
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* PineTab2
|
||||||
|
A few tweaks are specific to my PineTab2 tablet: getting a serial
|
||||||
|
console working at boot, exposing its sensors, and making it easy to
|
||||||
|
find on whatever network it’s connected to. Here’s the skeleton of the
|
||||||
|
=nixos.pinetab2= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.pinetab2 = {
|
||||||
|
<<kernel-params>>
|
||||||
|
<<sensors>>
|
||||||
|
<<avahi>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Serial Console
|
||||||
|
These kernel parameters get me a working serial console on the
|
||||||
|
tablet’s UART at boot, and point the kernel at the SD card’s root
|
||||||
|
filesystem by label rather than by a device path that can shift
|
||||||
|
around.
|
||||||
|
#+name: kernel-params
|
||||||
|
#+begin_src nix
|
||||||
|
boot.kernelParams = ["console=tty0" "console=ttyS2,1500000n8" "rootwait" "root=LABEL=NIXOS_SD" "rw"];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Sensors
|
||||||
|
Turning on the IIO (Industrial I/O) subsystem exposes the tablet’s
|
||||||
|
accelerometer and ambient light sensor, which is what lets things like
|
||||||
|
auto-rotate work.
|
||||||
|
#+name: sensors
|
||||||
|
#+begin_src nix
|
||||||
|
hardware.sensor.iio.enable = true;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Finding It on the Network
|
||||||
|
The tablet moves between networks a lot, so Avahi lets me reach it by
|
||||||
|
its =.local= hostname over mDNS instead of having to look up whatever IP
|
||||||
|
it was handed.
|
||||||
|
#+name: avahi
|
||||||
|
#+begin_src nix
|
||||||
|
services.avahi = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
cfg = config.mySystem.hardware.sound;
|
cfg = config.mySystem.hardware.sound;
|
||||||
in {
|
in {
|
||||||
options.mySystem.hardware.sound = {
|
options.mySystem.hardware.sound = {
|
||||||
enable = mkEnableOption "Whether to enable sounds with Pipewire";
|
|
||||||
noisetorch = mkEnableOption "Whether to activate noisetorch support";
|
noisetorch = mkEnableOption "Whether to activate noisetorch support";
|
||||||
scarlett.enable = mkEnableOption "Activate support for Scarlett sound card";
|
scarlett.enable = mkEnableOption "Activate support for Scarlett sound card";
|
||||||
alsa = mkOption {
|
alsa = mkOption {
|
||||||
@@ -35,7 +34,7 @@
|
|||||||
config = {
|
config = {
|
||||||
environment.systemPackages = mkIf cfg.scarlett.enable [pkgs.alsa-scarlett-gui];
|
environment.systemPackages = mkIf cfg.scarlett.enable [pkgs.alsa-scarlett-gui];
|
||||||
services = {
|
services = {
|
||||||
pipewire = mkIf cfg.enable {
|
pipewire = {
|
||||||
enable = true;
|
enable = true;
|
||||||
alsa = mkIf cfg.alsa {
|
alsa = mkIf cfg.alsa {
|
||||||
enable = mkDefault true;
|
enable = mkDefault true;
|
||||||
@@ -45,9 +44,7 @@
|
|||||||
};
|
};
|
||||||
pulseaudio.enable = false;
|
pulseaudio.enable = false;
|
||||||
};
|
};
|
||||||
programs.noisetorch = mkIf cfg.enable {
|
programs.noisetorch.enable = cfg.noisetorch;
|
||||||
enable = cfg.noisetorch;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
#+title: Sound
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* Sound
|
||||||
|
I use Pipewire for audio on my desktop machines, with a couple of
|
||||||
|
compatibility layers and bits of hardware-specific support switched on
|
||||||
|
as needed. Here’s the skeleton of the =nixos.sound= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.sound = {
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib; let
|
||||||
|
cfg = config.mySystem.hardware.sound;
|
||||||
|
in {
|
||||||
|
options.mySystem.hardware.sound = {
|
||||||
|
<<opt-noisetorch>>
|
||||||
|
<<opt-scarlett>>
|
||||||
|
<<opt-alsa>>
|
||||||
|
<<opt-jack>>
|
||||||
|
<<opt-package>>
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
<<scarlett-package>>
|
||||||
|
<<pipewire-config>>
|
||||||
|
<<noisetorch-config>>
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Noise Suppression
|
||||||
|
=noisetorch= toggles [[https://github.com/noisetorch/NoiseTorch][NoiseTorch]], a real-time microphone noise
|
||||||
|
suppression tool I use for calls, so I have an option for that.
|
||||||
|
#+name: opt-noisetorch
|
||||||
|
#+begin_src nix
|
||||||
|
noisetorch = mkEnableOption "Whether to activate noisetorch support";
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Passing it to NixOS is quite simple.
|
||||||
|
#+name: noisetorch-config
|
||||||
|
#+begin_src nix
|
||||||
|
programs.noisetorch.enable = cfg.noisetorch;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Scarlett Sound Card
|
||||||
|
=scarlett.enable= is for the machine =marpa= with a Focusrite Scarlett 2i2
|
||||||
|
audio interface plugged in; it only pulls in that card’s control GUI.
|
||||||
|
#+name: opt-scarlett
|
||||||
|
#+begin_src nix
|
||||||
|
scarlett.enable = mkEnableOption "Activate support for Scarlett sound card";
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
It is installed quite easily in enabled.
|
||||||
|
#+name: scarlett-package
|
||||||
|
#+begin_src nix
|
||||||
|
environment.systemPackages = mkIf cfg.scarlett.enable [pkgs.alsa-scarlett-gui];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Enabling Pipewire
|
||||||
|
Enabling Pipewire also means explicitly turning PulseAudio off, since
|
||||||
|
the two can’t run as the system’s sound server at the same time.
|
||||||
|
#+name: pipewire-config
|
||||||
|
#+begin_src nix
|
||||||
|
services = {
|
||||||
|
pipewire = {
|
||||||
|
enable = true;
|
||||||
|
alsa = mkIf cfg.alsa {
|
||||||
|
enable = mkDefault true;
|
||||||
|
support32Bit = mkDefault true;
|
||||||
|
};
|
||||||
|
jack.enable = mkDefault cfg.jack;
|
||||||
|
};
|
||||||
|
pulseaudio.enable = false;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** ALSA Compatibility
|
||||||
|
=alsa= enables Pipewire’s ALSA compatibility layer, on by default since
|
||||||
|
most of my audio software still expects ALSA.
|
||||||
|
#+name: opt-alsa
|
||||||
|
#+begin_src nix
|
||||||
|
alsa = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
example = true;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to enable ALSA support with Pipewire";
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** JACK Compatibility
|
||||||
|
=jack= enables Pipewire’s JACK compatibility layer, off by default since
|
||||||
|
only my production machine needs it.
|
||||||
|
#+name: opt-jack
|
||||||
|
#+begin_src nix
|
||||||
|
jack = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
example = true;
|
||||||
|
default = false;
|
||||||
|
description = "Whether to enable JACK support with Pipewire";
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Base Package
|
||||||
|
=package= picks which PulseAudio package to build things on top of.
|
||||||
|
#+name: opt-package
|
||||||
|
#+begin_src nix
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
example = pkgs.pulseaudio;
|
||||||
|
default = pkgs.pulseaudioFull;
|
||||||
|
description = "Which base package to use for PulseAudio";
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# -*- mode: org -*-
|
||||||
|
#+AUTHOR: Lucien Cartier-Tilet
|
||||||
|
#+EMAIL: lucien@phundrak.com
|
||||||
|
#+CREATOR: Lucien Cartier-Tilet
|
||||||
|
#+LANGUAGE: en
|
||||||
|
|
||||||
|
# ### ORG OPTIONS ##############################################################
|
||||||
|
|
||||||
|
#+options: H:4 broken_links:mark email:t ^:{} tex:dvisvgm toc:nil
|
||||||
|
#+KEYWORDS: dotfiles, linux, emacs, configuration, phundrak, drakpa
|
||||||
|
#+startup: content align hideblocks
|
||||||
|
#+property: header-args:emacs-lisp :noweb yes :exports none :eval yes :cache yes
|
||||||
|
#+property: header-args:nix :exports code :tangle no :noweb no-export
|
||||||
|
#+property: header-args:dot :dir img :exports results :eval yes :cache yes :class gentree
|
||||||
|
|
||||||
|
# ### MACROS ###################################################################
|
||||||
|
#+macro: phon @@html:/$1/@@
|
||||||
|
#+macro: newline @@html:<br>@@
|
||||||
|
#+macro: latex-html @@latex:$1@@@@html:$2@@
|
||||||
|
#+macro: v @@html:<span class=vertical>$1</span>@@
|
||||||
|
#+macro: begin-largetable @@html:<div class="largetable">@@
|
||||||
|
#+macro: end-largetable @@html:</div>@@
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{inputs, ...}: {
|
{inputs, ...}: {
|
||||||
flake-file.inputs.caelestia-shell = {
|
flake-file.inputs.caelestia-shell = {
|
||||||
url = "github:caelestia-dots/shell";
|
url = "github:caelestia-dots/shell?ref=stable";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
openmw
|
openmw
|
||||||
openttd-jgrpp
|
openttd-jgrpp
|
||||||
moonlight-qt
|
moonlight-qt
|
||||||
|
vintagestory
|
||||||
|
|
||||||
# Gnome stuff
|
# Gnome stuff
|
||||||
gnomeExtensions.tray-icons-reloaded
|
gnomeExtensions.tray-icons-reloaded
|
||||||
|
|||||||
@@ -27,10 +27,7 @@ in {
|
|||||||
|
|
||||||
mySystem = {
|
mySystem = {
|
||||||
boot = {
|
boot = {
|
||||||
kernel = {
|
kernel.cpuVendor = "amd";
|
||||||
hardened = true;
|
|
||||||
cpuVendor = "amd";
|
|
||||||
};
|
|
||||||
grub = {
|
grub = {
|
||||||
enable = true;
|
enable = true;
|
||||||
device = "/dev/sdb";
|
device = "/dev/sdb";
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ in {
|
|||||||
m.kernel
|
m.kernel
|
||||||
m.hardened
|
m.hardened
|
||||||
m.loader
|
m.loader
|
||||||
|
m.zfs
|
||||||
m.docker
|
m.docker
|
||||||
m.endlessh
|
m.endlessh
|
||||||
m.ssh
|
m.ssh
|
||||||
@@ -22,18 +23,12 @@ in {
|
|||||||
|
|
||||||
mySystem = {
|
mySystem = {
|
||||||
boot = {
|
boot = {
|
||||||
kernel = {
|
kernel.cpuVendor = "intel";
|
||||||
hardened = true;
|
|
||||||
cpuVendor = "intel";
|
|
||||||
};
|
|
||||||
grub = {
|
grub = {
|
||||||
enable = true;
|
enable = true;
|
||||||
device = "/dev/sdh";
|
device = "/dev/sdh";
|
||||||
};
|
};
|
||||||
zfs = {
|
zfs.pools = ["tank"];
|
||||||
enable = true;
|
|
||||||
pools = ["tank"];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
dev.docker = {
|
dev.docker = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ in {
|
|||||||
m.bluetooth
|
m.bluetooth
|
||||||
m.fingerprint
|
m.fingerprint
|
||||||
m.corne
|
m.corne
|
||||||
m.ibm-trackpoint
|
m.disable-ibm-trackpoint
|
||||||
m.opentablet
|
m.opentablet
|
||||||
m.sound
|
m.sound
|
||||||
m.i18n-input
|
m.i18n-input
|
||||||
@@ -32,7 +32,6 @@ in {
|
|||||||
|
|
||||||
mySystem = {
|
mySystem = {
|
||||||
boot = {
|
boot = {
|
||||||
plymouth.enable = true;
|
|
||||||
kernel = {
|
kernel = {
|
||||||
cpuVendor = "intel";
|
cpuVendor = "intel";
|
||||||
package = pkgs.linuxPackages;
|
package = pkgs.linuxPackages;
|
||||||
@@ -51,30 +50,15 @@ in {
|
|||||||
podman.enable = true;
|
podman.enable = true;
|
||||||
autoprune.enable = true;
|
autoprune.enable = true;
|
||||||
};
|
};
|
||||||
hardware = {
|
|
||||||
bluetooth.enable = true;
|
|
||||||
fingerprint.enable = true;
|
|
||||||
input = {
|
|
||||||
corne.allowHidAccess = true;
|
|
||||||
ibmTrackpoint.disable = true;
|
|
||||||
opentablet.enable = true;
|
|
||||||
};
|
|
||||||
sound.enable = true;
|
|
||||||
};
|
|
||||||
i18n.input.enable = true;
|
|
||||||
misc.keymap = "fr-bepo";
|
misc.keymap = "fr-bepo";
|
||||||
networking = {
|
networking = {
|
||||||
hostname = "gampo";
|
hostname = "gampo";
|
||||||
id = "0630b33f";
|
id = "0630b33f";
|
||||||
};
|
};
|
||||||
packages = {
|
packages.nix = {
|
||||||
appimage.enable = true;
|
|
||||||
flatpak.enable = true;
|
|
||||||
nix = {
|
|
||||||
gc.automatic = true;
|
gc.automatic = true;
|
||||||
nix-ld.enable = true;
|
nix-ld.enable = true;
|
||||||
};
|
};
|
||||||
};
|
|
||||||
services = {
|
services = {
|
||||||
fwupd.enable = true;
|
fwupd.enable = true;
|
||||||
ssh.enable = true;
|
ssh.enable = true;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ in {
|
|||||||
# m.niri
|
# m.niri
|
||||||
m.waydroid
|
m.waydroid
|
||||||
m.xserver
|
m.xserver
|
||||||
|
m.amdgpu
|
||||||
m.docker
|
m.docker
|
||||||
m.qemu
|
m.qemu
|
||||||
m.bluetooth
|
m.bluetooth
|
||||||
@@ -72,7 +73,6 @@ in {
|
|||||||
|
|
||||||
mySystem = {
|
mySystem = {
|
||||||
boot = {
|
boot = {
|
||||||
plymouth.enable = true;
|
|
||||||
kernel = {
|
kernel = {
|
||||||
cpuVendor = "amd";
|
cpuVendor = "amd";
|
||||||
v4l2loopback.enable = true;
|
v4l2loopback.enable = true;
|
||||||
@@ -84,11 +84,11 @@ in {
|
|||||||
};
|
};
|
||||||
desktop = {
|
desktop = {
|
||||||
hyprland.enable = true;
|
hyprland.enable = true;
|
||||||
niri.enable = true;
|
|
||||||
waydroid.enable = true;
|
waydroid.enable = true;
|
||||||
xserver = {
|
xserver = {
|
||||||
enable = true;
|
enable = true;
|
||||||
de = "gnome";
|
de = "gnome";
|
||||||
|
videoDrivers = ["amdgpu"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
dev = {
|
dev = {
|
||||||
@@ -97,23 +97,14 @@ in {
|
|||||||
podman.enable = true;
|
podman.enable = true;
|
||||||
autoprune.enable = true;
|
autoprune.enable = true;
|
||||||
};
|
};
|
||||||
qemu.enable = true;
|
|
||||||
};
|
};
|
||||||
hardware = {
|
hardware = {
|
||||||
amdgpu.enable = true;
|
|
||||||
bluetooth.enable = true;
|
|
||||||
input = {
|
|
||||||
corne.allowHidAccess = true;
|
|
||||||
opentablet.enable = true;
|
|
||||||
};
|
|
||||||
sound = {
|
sound = {
|
||||||
enable = true;
|
|
||||||
noisetorch = true;
|
noisetorch = true;
|
||||||
jack = true;
|
jack = true;
|
||||||
scarlett.enable = true;
|
scarlett.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
i18n.input.enable = true;
|
|
||||||
misc.keymap = "fr-bepo";
|
misc.keymap = "fr-bepo";
|
||||||
networking = {
|
networking = {
|
||||||
hostname = "marpa";
|
hostname = "marpa";
|
||||||
@@ -126,11 +117,7 @@ in {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
packages = {
|
packages.nix.nix-ld.enable = true;
|
||||||
appimage.enable = true;
|
|
||||||
flatpak.enable = true;
|
|
||||||
nix.nix-ld.enable = true;
|
|
||||||
};
|
|
||||||
services = {
|
services = {
|
||||||
fwupd.enable = true;
|
fwupd.enable = true;
|
||||||
harmonia = {
|
harmonia = {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ in {
|
|||||||
m.niri
|
m.niri
|
||||||
m.waydroid
|
m.waydroid
|
||||||
m.xserver
|
m.xserver
|
||||||
m.amdgpu
|
|
||||||
m.docker
|
m.docker
|
||||||
m.bluetooth
|
m.bluetooth
|
||||||
m.opentablet
|
m.opentablet
|
||||||
@@ -38,27 +37,16 @@ in {
|
|||||||
podman.enable = true;
|
podman.enable = true;
|
||||||
autoprune.enable = true;
|
autoprune.enable = true;
|
||||||
};
|
};
|
||||||
hardware = {
|
|
||||||
bluetooth.enable = true;
|
|
||||||
input.opentablet.enable = true;
|
|
||||||
pinetab2.enable = true;
|
|
||||||
sound.enable = true;
|
|
||||||
};
|
|
||||||
i18n.input.enable = true;
|
|
||||||
misc.keymap = "fr-bepo";
|
misc.keymap = "fr-bepo";
|
||||||
networking = {
|
networking = {
|
||||||
hostname = "pinetab2";
|
hostname = "pinetab2";
|
||||||
id = "99a11b15";
|
id = "99a11b15";
|
||||||
wifi.disablePowersave = true;
|
wifi.disablePowersave = true;
|
||||||
};
|
};
|
||||||
packages = {
|
packages.nix = {
|
||||||
appimage.enable = true;
|
|
||||||
flatpak.enable = true;
|
|
||||||
nix = {
|
|
||||||
gc.automatic = true;
|
gc.automatic = true;
|
||||||
nix-ld.enable = true;
|
nix-ld.enable = true;
|
||||||
};
|
};
|
||||||
};
|
|
||||||
services.ssh.enable = true;
|
services.ssh.enable = true;
|
||||||
users = {
|
users = {
|
||||||
root.disablePassword = true;
|
root.disablePassword = true;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ in {
|
|||||||
m.kernel
|
m.kernel
|
||||||
m.hardened
|
m.hardened
|
||||||
m.loader
|
m.loader
|
||||||
|
m.zfs
|
||||||
m.docker
|
m.docker
|
||||||
m.calibre
|
m.calibre
|
||||||
m.endlessh
|
m.endlessh
|
||||||
@@ -18,14 +19,8 @@ in {
|
|||||||
|
|
||||||
mySystem = {
|
mySystem = {
|
||||||
boot = {
|
boot = {
|
||||||
kernel = {
|
kernel.cpuVendor = "amd";
|
||||||
hardened = true;
|
zfs.pools = ["tank"];
|
||||||
cpuVendor = "amd";
|
|
||||||
};
|
|
||||||
zfs = {
|
|
||||||
enable = true;
|
|
||||||
pools = ["tank"];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
dev.docker.enable = true;
|
dev.docker.enable = true;
|
||||||
misc.keymap = "fr-bepo";
|
misc.keymap = "fr-bepo";
|
||||||
|
|||||||
+5
-15
@@ -1,24 +1,14 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.i18n-input = {
|
flake.modules.nixos.i18n-input = {pkgs, ...}: {
|
||||||
lib,
|
i18n.inputMethod = {
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.mySystem.i18n.input;
|
|
||||||
in {
|
|
||||||
options.mySystem.i18n.input.enable = mkEnableOption "Enable i18n input with fcitx5";
|
|
||||||
|
|
||||||
config.i18n.inputMethod = mkIf cfg.enable {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
type = "fcitx5";
|
type = "fcitx5";
|
||||||
fcitx5.addons = with pkgs; [
|
fcitx5.addons = with pkgs; [
|
||||||
fcitx5-gtk
|
fcitx5-gtk
|
||||||
fcitx5-mozc-ut # Japanese input support
|
fcitx5-mozc-ut
|
||||||
fcitx5-nord
|
fcitx5-nord
|
||||||
fcitx5-table-other # X-SAMPA to IPA support
|
fcitx5-table-other
|
||||||
qt6Packages.fcitx5-chinese-addons # allow to load table addons
|
qt6Packages.fcitx5-chinese-addons
|
||||||
qt6Packages.fcitx5-configtool
|
qt6Packages.fcitx5-configtool
|
||||||
qt6Packages.fcitx5-with-addons
|
qt6Packages.fcitx5-with-addons
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#+title: Input Methods
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* Input Methods
|
||||||
|
I type in more than one script, so I need a proper input method
|
||||||
|
framework rather than relying on whatever the desktop environment
|
||||||
|
ships with. Plus, the default /AFNOR bépo/ layout is currently buggy,
|
||||||
|
with some dead keys not working properly, such as =AltGr+s=, but it
|
||||||
|
isn’t with fcitx5. Here’s the =nixos.i18n-input= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.i18n-input = {pkgs, ...}: {
|
||||||
|
i18n.inputMethod = {
|
||||||
|
<<enable-fcitx5>>
|
||||||
|
<<fcitx5-addons>>
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Enabling fcitx5
|
||||||
|
[[https://fcitx-im.org/wiki/Fcitx_5][fcitx5]] is the input method framework I’ve settled on; it covers
|
||||||
|
everything from CJK input to custom table-based methods.
|
||||||
|
#+name: enable-fcitx5
|
||||||
|
#+begin_src nix
|
||||||
|
enable = true;
|
||||||
|
type = "fcitx5";
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Addons
|
||||||
|
=fcitx5-gtk= gets fcitx5 working inside GTK applications, and the Qt
|
||||||
|
equivalents (=fcitx5-configtool=, =fcitx5-with-addons=) do the same for Qt
|
||||||
|
ones whilst also giving me a GUI to configure it all. =fcitx5-mozc-ut=
|
||||||
|
adds Japanese input through Mozc, and
|
||||||
|
=qt6Packages.fcitx5-chinese-addons= adds the table addons Chinese input
|
||||||
|
methods need. I don’t actually need this package for Chinese itself,
|
||||||
|
but it is somehow necessary for the X-SAMPA input method, which I get
|
||||||
|
from =fcitx5-table-other=. I have it to type IPA on the fly when working
|
||||||
|
on my constructed languages. Lastly, =fcitx5-nord= just reskins the UI
|
||||||
|
to match the rest of my setup.
|
||||||
|
#+name: fcitx5-addons
|
||||||
|
#+begin_src nix
|
||||||
|
fcitx5.addons = with pkgs; [
|
||||||
|
fcitx5-gtk
|
||||||
|
fcitx5-mozc-ut
|
||||||
|
fcitx5-nord
|
||||||
|
fcitx5-table-other
|
||||||
|
qt6Packages.fcitx5-chinese-addons
|
||||||
|
qt6Packages.fcitx5-configtool
|
||||||
|
qt6Packages.fcitx5-with-addons
|
||||||
|
];
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#+title: Locale
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* Locale
|
||||||
|
I want my system messages in English, but everything else about how
|
||||||
|
dates, money and paper sizes are formatted to reflect where I actually
|
||||||
|
live. Here’s the =nixos.locale= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.locale = {
|
||||||
|
i18n = {
|
||||||
|
<<default-locale>>
|
||||||
|
<<extra-locale-settings>>
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Default Locale
|
||||||
|
=en_DK.UTF-8= is a well-known trick: English messages and collation, but
|
||||||
|
ISO 8601 dates and sane metric units, instead of =en_US='s nonsense
|
||||||
|
MM/DD/YYYY and imperial units.
|
||||||
|
#+name: default-locale
|
||||||
|
#+begin_src nix
|
||||||
|
defaultLocale = "en_DK.UTF-8";
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Regional Settings
|
||||||
|
Since I live in France, I want addresses, money, paper size, phone
|
||||||
|
numbers and the like to follow French conventions instead of whatever
|
||||||
|
=en_DK= would otherwise pick.
|
||||||
|
#+name: extra-locale-settings
|
||||||
|
#+begin_src nix
|
||||||
|
extraLocaleSettings = {
|
||||||
|
LC_ADDRESS = "fr_FR.UTF-8";
|
||||||
|
LC_IDENTIFICATION = "fr_FR.UTF-8";
|
||||||
|
LC_MEASUREMENT = "fr_FR.UTF-8";
|
||||||
|
LC_MONETARY = "fr_FR.UTF-8";
|
||||||
|
LC_NAME = "fr_FR.UTF-8";
|
||||||
|
LC_NUMERIC = "fr_FR.UTF-8";
|
||||||
|
LC_PAPER = "fr_FR.UTF-8";
|
||||||
|
LC_TELEPHONE = "fr_FR.UTF-8";
|
||||||
|
LC_TIME = "fr_FR.UTF-8";
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
#+title: P’undrak’s Litterate Nix Config
|
||||||
|
#+setupfile: headers
|
||||||
|
#+property: header-args:emacs-lisp :lexical t :exports none :tangle no
|
||||||
|
|
||||||
|
* Index
|
||||||
|
Hi, I’m P’undrak (pronounced /PUN-drak/, or more exactly {{{phon(pʰynɖak̚)}}}),
|
||||||
|
also known as Lucien Cartier-Tilet. If you want to know more about me,
|
||||||
|
you can head to my [[https://phundrak.com/en][main website]].
|
||||||
|
|
||||||
|
This website documents my entire Linux configuration, managed through
|
||||||
|
NixOS. Most of my programs are configured through Nix, following the
|
||||||
|
[[https://github.com/Doc-Steve/dendritic-design-with-flake-parts][dendritic pattern]].
|
||||||
|
|
||||||
|
To give you a tl;dr, this basically means that each aspect of my
|
||||||
|
configuration (be it a concept or an application) tries to only have a
|
||||||
|
single source of truth. But as you can see with my Emacs
|
||||||
|
configuration, some aspects can be quite extensive and require several
|
||||||
|
pages to be properly organised.
|
||||||
|
|
||||||
|
** License
|
||||||
|
See [[https://labs.phundrak.com/phundrak/dotfiles/src/branch/master/LICENSE.org][the repository’s license file]].
|
||||||
|
|
||||||
|
** Note on What a Literate Configuration Is
|
||||||
|
As implied by the title of this website, my configuration is a
|
||||||
|
litterate one. This means that every page of this website comes from
|
||||||
|
an Emacs org-mode file, and the code you see as code blocks are the
|
||||||
|
actual source of my configuration.
|
||||||
|
|
||||||
|
Org-mode offers to “tangle” these code blocks into full files, which
|
||||||
|
can then be used as any other source file. If you visit this website’s
|
||||||
|
repository, you will find the source org files alongside their
|
||||||
|
resulting Nix file if any is generated by said file. For instance,
|
||||||
|
this very page generates my =modules/default.nix= file, as we’ll see
|
||||||
|
below.
|
||||||
|
|
||||||
|
This also implies heavy usage of the [[https://orgmode.org/manual/Noweb-Reference-Syntax.html][noweb]] syntax. If you encounter
|
||||||
|
some code that looks ~<<like-this>>~, org-mode will replace this snippet
|
||||||
|
with another code snippet declared elsewhere in my configuration. If
|
||||||
|
you see some code that looks ~<<like-this()>>~, some generating code
|
||||||
|
will run and replace this piece of text with the text generated. A
|
||||||
|
quick example:
|
||||||
|
#+begin_src elisp
|
||||||
|
(defun hello ()
|
||||||
|
<<generate-docstring()>>
|
||||||
|
<<print-hello>>)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Will instead appear as
|
||||||
|
#+begin_src emacs-lisp :noweb yes
|
||||||
|
(defun hello ()
|
||||||
|
<<generate-docstring()>>
|
||||||
|
<<print-hello>>)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
This is because I have the block of code below named
|
||||||
|
~generate-docstring~ which generates an output, which replaces its noweb
|
||||||
|
tag. You can recognize noweb snippets generating code with the
|
||||||
|
parenthesis. Often, such blocks aren’t visible in my HTML exports, but
|
||||||
|
you can still see them if you open the actual org source file.
|
||||||
|
#+name: generate-docstring
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(concat "\""
|
||||||
|
"Print \\\"Hello World!\\\" in the minibuffer."
|
||||||
|
"\"")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
On the other hand, noweb snippets without parenthesis simply replace
|
||||||
|
the snippet with the equivalent named code block. For instance the one
|
||||||
|
below is named ~print-hello~ and is placed as-is in the target source
|
||||||
|
block.
|
||||||
|
#+name: print-hello
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(message "Hello World!")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Root Nix Configuration
|
||||||
|
As this configuration uses [[https://flake.parts/][flake-parts]] and [[https://flake-file.denful.dev/][flake-file]], I need a
|
||||||
|
=modules/default.nix= which defines how to manage my config.
|
||||||
|
|
||||||
|
For the record, I use [[https://github.com/nix-community/nh][nh]] to compile my configuration and switch to
|
||||||
|
newer generations of my OS and home. This allows me to simply run =nh
|
||||||
|
os switch= to upgrade my system, or =nh home switch= to upgrade my
|
||||||
|
[[https://nix-community.github.io/home-manager/][home-manager]] configuration. This, therefore, requires having [[https://nixos.wiki/wiki/flakes][flakes]]
|
||||||
|
outputs in the form of =nixosConfigurations.marpa= (with =marpa= being the
|
||||||
|
hostname of a machine) and =homeConfigurations.phundrak= or
|
||||||
|
=homeConfigurations.phundrak@marpa= (with =phundrak= being the username of
|
||||||
|
one of the users of a machine).
|
||||||
|
|
||||||
|
But first things first, let’s declare the closure that will
|
||||||
|
encapsulate the rest of the file:
|
||||||
|
#+begin_src nix :tangle default.nix
|
||||||
|
{
|
||||||
|
inputs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
<<modules-imports>>
|
||||||
|
|
||||||
|
<<options-home>>
|
||||||
|
|
||||||
|
config = {
|
||||||
|
<<flake-inputs>>
|
||||||
|
<<dev-arch>>
|
||||||
|
|
||||||
|
flake.lib = {
|
||||||
|
<<lib-mkNixos>>
|
||||||
|
<<lib-mkHome>>
|
||||||
|
<<lib-mkPinetab>>
|
||||||
|
};
|
||||||
|
|
||||||
|
<<configs-decl>>
|
||||||
|
<<devshell>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
To get our configuration to work, we need to import the modules from
|
||||||
|
flake-parts and flake-file.
|
||||||
|
#+name: modules-imports
|
||||||
|
#+begin_src nix
|
||||||
|
imports = [
|
||||||
|
inputs.flake-parts.flakeModules.modules
|
||||||
|
inputs.flake-file.flakeModules.default
|
||||||
|
];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Now, we can declare an option to make =homeConfigurations= available as
|
||||||
|
an output for our flakes.
|
||||||
|
#+name: options-home
|
||||||
|
#+begin_src nix
|
||||||
|
options.flake.homeConfigurations = lib.mkOption {
|
||||||
|
type = lib.types.lazyAttrsOf lib.types.raw;
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Setting Things Up
|
||||||
|
We need to declare a few inputs for our flake, thanks to
|
||||||
|
flake-file. The first one is =flake-utils=, which allows me to easily
|
||||||
|
declare my development shell for this repository both for my x86-64
|
||||||
|
machines and my aarch64 tablet, a PineTab 2. Then, speaking of the
|
||||||
|
PineTab, I need some specific nixpkgs input, to handle a bug in the
|
||||||
|
compilation of the kernel, as well as the flake =rockchip= to support
|
||||||
|
said kernel.
|
||||||
|
#+name: flake-inputs
|
||||||
|
#+begin_src nix
|
||||||
|
flake-file.inputs = {
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
nixpkgsPinetab2Kernel.url = "github:nixos/nixpkgs/e73de5be04e0eff4190a1432b946d469c794e7b4";
|
||||||
|
rockchip = {
|
||||||
|
url = "github:raboof/nixos-rockchip/pinetab-linux-7.0";
|
||||||
|
inputs.utils.follows = "flake-utils";
|
||||||
|
inputs.nixpkgsStable.follows = "nixpkgsStable";
|
||||||
|
inputs.nixpkgsUnstable.follows = "nixpkgsPinetab2Kernel";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
As I said, I support two architectures for my development shell, so
|
||||||
|
let’s declare them.
|
||||||
|
#+name: dev-arch
|
||||||
|
#+begin_src nix
|
||||||
|
systems = ["x86_64-linux" "aarch64-linux"];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Now, we can declare some functions for our flake. These three
|
||||||
|
functions’ role is to create the output of each machine and user as
|
||||||
|
required. First, let’s create the function to get a machine’s
|
||||||
|
configuration based on its name.
|
||||||
|
#+name: lib-mkNixos
|
||||||
|
#+begin_src nix
|
||||||
|
mkNixos = system: name: {
|
||||||
|
${name} = inputs.nixpkgs.lib.nixosSystem {
|
||||||
|
modules = [
|
||||||
|
config.flake.modules.nixos.${name}
|
||||||
|
{nixpkgs.hostPlatform = lib.mkDefault system;}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
What this does is basically declare a Nix system named after the
|
||||||
|
host’s name, created with its module (located in =modules/hosts/=) and
|
||||||
|
the related nixpkgs with the appropriate architecture. For now, the
|
||||||
|
only architecture used with this function is x86-64, but I’m not
|
||||||
|
excluding the possibility to have other hosts using an ARM CPU.
|
||||||
|
|
||||||
|
=mkHome= is somewhat similar: it declares a home-manager module,
|
||||||
|
importing the module related to the user and the machine it will be
|
||||||
|
deployed on.
|
||||||
|
#+name: lib-mkHome
|
||||||
|
#+begin_src nix
|
||||||
|
mkHome = system: userName: hostName: {
|
||||||
|
"${userName}@${hostName}" = inputs.home-manager.lib.homeManagerConfiguration {
|
||||||
|
pkgs = inputs.nixpkgs.legacyPackages.${system};
|
||||||
|
extraSpecialArgs = {
|
||||||
|
inherit inputs;
|
||||||
|
bunBaseline = config.flake.packages.${system}.bun-baseline;
|
||||||
|
};
|
||||||
|
modules = [config.flake.modules.homeManager."${userName}-${hostName}"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
You may notice the declaration of =bunBaseline=. This is because of my
|
||||||
|
ThinkPad x220; the default binary distributed for Bun uses CPU
|
||||||
|
instructions that are more recent than this laptop’s CPU, which
|
||||||
|
results in fatal errors trying to run it. Therefore, =bunBaseline= is
|
||||||
|
here to either compile Bun on my ThinkPad with the correct instruction
|
||||||
|
set, or simply use a prepackaged Bun if the host supports it.
|
||||||
|
|
||||||
|
Lastly, I have a function dedicated to building NixOS on my PineTab 2.
|
||||||
|
#+name: lib-mkPinetab
|
||||||
|
#+begin_src nix
|
||||||
|
mkPinetab = buildPlatform: variantModule: {
|
||||||
|
pinetab2 = inputs.nixpkgs.lib.nixosSystem {
|
||||||
|
system = "aarch64-linux";
|
||||||
|
modules = [
|
||||||
|
inputs.rockchip.nixosModules.sdImageRockchip
|
||||||
|
inputs.rockchip.nixosModules.dtOverlayPCIeFix
|
||||||
|
inputs.rockchip.nixosModules.noZFS
|
||||||
|
config.flake.modules.nixos.pinetab2-base
|
||||||
|
variantModule
|
||||||
|
{
|
||||||
|
rockchip.uBoot = inputs.rockchip.packages.${buildPlatform}.uBootPineTab2;
|
||||||
|
boot.kernelPackages =
|
||||||
|
inputs.rockchip.legacyPackages.${buildPlatform}.kernel_linux_7_0_pinetab_unstable;
|
||||||
|
hardware.firmware = [inputs.rockchip.packages.aarch64-linux.bes2600];
|
||||||
|
nixpkgs.config.allowUnfreePredicate = pkg:
|
||||||
|
builtins.elem (inputs.nixpkgs.lib.getName pkg) ["bes2600-firmware"];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
I won’t go into too much details here, but it mostly imports the
|
||||||
|
modules required to run NixOS on the Pinetab as well as explicitly
|
||||||
|
import the bes2600 firmware module to make Bluetooth and Wi-Fi
|
||||||
|
available on the tablet.
|
||||||
|
|
||||||
|
*** Declaring the Actual Outputs
|
||||||
|
With all that being said, we can now actually declare our
|
||||||
|
configurations. You can see below the table of hosts I have, with
|
||||||
|
their CPU architecture, and which users are present on the system.
|
||||||
|
|
||||||
|
#+name: table-hosts
|
||||||
|
| Host | Architecture | Users | Comment |
|
||||||
|
|----------+---------------+-----------------+------------------|
|
||||||
|
| marpa | x86_64-linux | phundrak | Main workstation |
|
||||||
|
| gampo | x86_64-linux | phundrak | Thinkpad x220 |
|
||||||
|
| tilo | x86_64-linux | phundrak | Home Server |
|
||||||
|
| elcafe | x86_64-linux | phundrak, creug | Server |
|
||||||
|
| NaroMk3 | x86_64-linux | phundrak | Cloud Server |
|
||||||
|
| pinetab2 | aarch64-linux | phundrak | PineTab 2 tablet |
|
||||||
|
|
||||||
|
#+name: make-hosts
|
||||||
|
#+begin_src emacs-lisp :exports none :var hosts=table-hosts :cache yes
|
||||||
|
(mapconcat
|
||||||
|
(lambda (line)
|
||||||
|
(let ((hostname (car line))
|
||||||
|
(arch (nth 1 line)))
|
||||||
|
(format "(config.flake.lib.mkNixos \"%s\" \"%s\")"
|
||||||
|
arch
|
||||||
|
hostname)))
|
||||||
|
(-filter (lambda (host) (not (string= "pinetab2" (car host))))
|
||||||
|
hosts)
|
||||||
|
"\n")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[f5f8b3a89622e7526a83cbf722c4b7c77ff7bd86]: make-hosts
|
||||||
|
: (config.flake.lib.mkNixos "x86_64-linux" "marpa")
|
||||||
|
: (config.flake.lib.mkNixos "x86_64-linux" "gampo")
|
||||||
|
: (config.flake.lib.mkNixos "x86_64-linux" "tilo")
|
||||||
|
: (config.flake.lib.mkNixos "x86_64-linux" "elcafe")
|
||||||
|
: (config.flake.lib.mkNixos "x86_64-linux" "NaroMk3")
|
||||||
|
|
||||||
|
#+name: make-home
|
||||||
|
#+begin_src emacs-lisp :exports none :var hosts=table-hosts :cache yes
|
||||||
|
(require 's)
|
||||||
|
|
||||||
|
(mapconcat
|
||||||
|
(lambda (line)
|
||||||
|
(let ((hostname (car line))
|
||||||
|
(arch (nth 1 line))
|
||||||
|
(users (mapcar #'s-trim (s-split "," (nth 2 line) t))))
|
||||||
|
(mapconcat (lambda (user)
|
||||||
|
(format "(config.flake.lib.mkHome \"%s\" \"%s\" \"%s\")"
|
||||||
|
arch user hostname))
|
||||||
|
users
|
||||||
|
"\n")))
|
||||||
|
hosts
|
||||||
|
"\n")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[301fccb07591fffc8d7bdfd7d2958602150aa688]: make-home
|
||||||
|
: (config.flake.lib.mkHome "x86_64-linux" "phundrak" "marpa")
|
||||||
|
: (config.flake.lib.mkHome "x86_64-linux" "phundrak" "gampo")
|
||||||
|
: (config.flake.lib.mkHome "x86_64-linux" "phundrak" "tilo")
|
||||||
|
: (config.flake.lib.mkHome "x86_64-linux" "phundrak" "elcafe")
|
||||||
|
: (config.flake.lib.mkHome "x86_64-linux" "creug" "elcafe")
|
||||||
|
: (config.flake.lib.mkHome "x86_64-linux" "phundrak" "NaroMk3")
|
||||||
|
: (config.flake.lib.mkHome "aarch64-linux" "phundrak" "pinetab2")
|
||||||
|
|
||||||
|
This translates into this Nix code.
|
||||||
|
#+name: configs-decl
|
||||||
|
#+begin_src nix :noweb yes
|
||||||
|
flake.nixosConfigurations = lib.mkMerge [
|
||||||
|
<<make-hosts()>>
|
||||||
|
(config.flake.lib.mkPinetab "x86_64-linux" config.flake.modules.nixos.pinetab2-gnome)
|
||||||
|
];
|
||||||
|
flake.homeConfigurations = lib.mkMerge [
|
||||||
|
<<make-home()>>
|
||||||
|
];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Development Shell
|
||||||
|
Lastly, here is the declaration of my development shell. It really is
|
||||||
|
only useful if I’m on a new machine or a machine that is not quite up
|
||||||
|
to date and misses some packages I rely on to work on my dotfiles.
|
||||||
|
Namely, these are =nh= (which I mentioned above), Jujutsu, =jj-cz= (a
|
||||||
|
Commitizen alternative for Jujutsu I’m working on), and Git itself as
|
||||||
|
a fallback.
|
||||||
|
#+name: devshell
|
||||||
|
#+begin_src nix
|
||||||
|
perSystem = {
|
||||||
|
pkgs,
|
||||||
|
system,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
formatter = pkgs.alejandra;
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.nh
|
||||||
|
pkgs.jujutsu
|
||||||
|
pkgs.git
|
||||||
|
inputs.jj-cz.packages.${system}.default
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
+1
-1
@@ -11,5 +11,5 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
flake-file.outputs = "dendritic";
|
flake-file.outputs = "dendritic";
|
||||||
flake-file.description = "NixOS and Home Manager configuration of phundrak";
|
flake-file.description = "NixOS and Home Manager configuration of P'undrak";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#+title: Flake File Setup
|
||||||
|
#+setupfile: headers
|
||||||
|
|
||||||
|
* Flake File Setup
|
||||||
|
This configuration uses [[https://flake-file.denful.dev/][flake-file]]. This means my =flake.nix= file is
|
||||||
|
modular, as it allows me to define my inputs where I need them, and
|
||||||
|
not necessarily all at the same place. This can be a bit unusual for
|
||||||
|
people who are new to it, but trust me, it’s well worth it.
|
||||||
|
|
||||||
|
I’ll simply set up the outputs, a single one named =dendritic=, and the
|
||||||
|
description here, as nothing is too complicated.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
<<inputs>>
|
||||||
|
flake-file.outputs = "dendritic";
|
||||||
|
flake-file.description = "NixOS and Home Manager configuration of P'undrak";
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Inputs
|
||||||
|
Some flake imputs are required globally, as they are used by default
|
||||||
|
by this configuration and some hosts.
|
||||||
|
|
||||||
|
#+name: inputs
|
||||||
|
#+begin_src nix
|
||||||
|
flake-file.inputs = {
|
||||||
|
<<inputs-nixpkgs>>
|
||||||
|
<<inputs-flake-parts>>
|
||||||
|
<<inputs-flake-file>>
|
||||||
|
<<inputs-import-tree>>
|
||||||
|
<<inputs-home-manager>>
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
First, we get to nixpkgs, which
|
||||||
|
is quite necessary to get NixOS up and running: it gives access to
|
||||||
|
Nix’s packages. I also have a =nixpkgsStable= input for the kernel of my
|
||||||
|
PineTab 2 tablet. Otherwise, I use Nix unstable.
|
||||||
|
|
||||||
|
#+name: inputs-nixpkgs
|
||||||
|
#+begin_src nix
|
||||||
|
nixpkgsStable.url = "nixpkgs/nixos-25.11";
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Next, I need some inputs for my dendritic config. =flake-parts= is the
|
||||||
|
heart of it: it’s a framework for writing flake modules that can
|
||||||
|
easily be put together as a single module defining an entire system,
|
||||||
|
such as a home configuration or a host configuration.
|
||||||
|
#+name: inputs-flake-parts
|
||||||
|
#+begin_src nix
|
||||||
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Next, we have flake-file, which permits the modularisation of my
|
||||||
|
=flake.nix= file itself, as mentioned abve.
|
||||||
|
#+name: inputs-flake-file
|
||||||
|
#+begin_src nix
|
||||||
|
flake-file.url = "github:vic/flake-file";
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Next, we have =import-tree=, which automatically imports my Nix files,
|
||||||
|
making all modules globally known.
|
||||||
|
#+name: inputs-import-tree
|
||||||
|
#+begin_src nix
|
||||||
|
import-tree.url = "github:vic/import-tree";
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
And last but not least, =home-manager=. This allows me to manage the
|
||||||
|
programs of me as the user of my machine and not necessarily the
|
||||||
|
machine itself, as well as their configuration. As such, I can upgrade
|
||||||
|
a machine’s system without touching my environment, and the inverse is
|
||||||
|
true. However, it’s important to keep them in sync when it comes to
|
||||||
|
major upgrades of NixOS, so home-manager will follow the system’s
|
||||||
|
version.
|
||||||
|
#+name: inputs-home-manager
|
||||||
|
#+begin_src nix
|
||||||
|
home-manager = {
|
||||||
|
url = "github:nix-community/home-manager";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
+5
-9
@@ -7,31 +7,27 @@
|
|||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.mySystem.misc;
|
cfg = config.mySystem.misc;
|
||||||
in {
|
in {
|
||||||
options.mySystem.misc = {
|
options.mySystem.misc.timezone = mkOption {
|
||||||
timezone = mkOption {
|
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "Europe/Paris";
|
default = "Europe/Paris";
|
||||||
};
|
};
|
||||||
keymap = mkOption {
|
options.mySystem.misc.keymap = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "fr";
|
default = "fr";
|
||||||
example = "fr-bepo";
|
example = "fr-bepo";
|
||||||
description = "Keymap to use in the TTY console";
|
description = "Keymap to use in the TTY console";
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
boot.tmp.cleanOnBoot = true;
|
|
||||||
console.keyMap = cfg.keymap;
|
console.keyMap = cfg.keymap;
|
||||||
time.timeZone = cfg.timezone;
|
time.timeZone = cfg.timezone;
|
||||||
|
services.envfs.enable = true;
|
||||||
|
services.orca.enable = false;
|
||||||
|
boot.tmp.cleanOnBoot = true;
|
||||||
environment.pathsToLink = [
|
environment.pathsToLink = [
|
||||||
"/share/bash-completion"
|
"/share/bash-completion"
|
||||||
"/share/zsh"
|
"/share/zsh"
|
||||||
];
|
];
|
||||||
services = {
|
|
||||||
orca.enable = false;
|
|
||||||
envfs.enable = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
#+title: Misc NixOS Configurations
|
||||||
|
#+setupfile: headers
|
||||||
|
|
||||||
|
* Misc NixOS Configurations
|
||||||
|
|
||||||
|
This module hosts some misc configuration I am unsure where to put
|
||||||
|
elsewhere than here. Don’t expect this file to be coherent, but expect
|
||||||
|
it to be quite short.
|
||||||
|
|
||||||
|
This module declares the aspect =nixos.misc=, which is used by all my
|
||||||
|
hosts.
|
||||||
|
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.misc = {
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib; let
|
||||||
|
cfg = config.mySystem.misc;
|
||||||
|
in {
|
||||||
|
<<timezone-option>>
|
||||||
|
<<layout-option>>
|
||||||
|
|
||||||
|
config = {
|
||||||
|
<<layout-config>>
|
||||||
|
<<timezone-config>>
|
||||||
|
<<envfs>>
|
||||||
|
<<orca>>
|
||||||
|
<<clean-tmp>>
|
||||||
|
<<completion>>
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** System Timezone
|
||||||
|
First, let me declare the timezone. I’ll set it as an option, as not
|
||||||
|
all my machines live in the same place, but I’ll default to
|
||||||
|
Metropolitan France’s timezone.
|
||||||
|
#+name: timezone-option
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.misc.timezone = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "Europe/Paris";
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Now, I can set it for my system.
|
||||||
|
#+name: timezone-config
|
||||||
|
#+begin_src nix
|
||||||
|
time.timeZone = cfg.timezone;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TTY Keyboard Layout
|
||||||
|
Now, I can set the TTY’s keyboard config. Most of my machines use the
|
||||||
|
Bépo layout everywhere, but I do share one whose owner doesn’t use it,
|
||||||
|
so I’ll let this as an option to be set, defaulting to the default
|
||||||
|
French layout.
|
||||||
|
#+name: layout-option
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.misc.keymap = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "fr";
|
||||||
|
example = "fr-bepo";
|
||||||
|
description = "Keymap to use in the TTY console";
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Now, I can set it on my system.
|
||||||
|
#+name: layout-config
|
||||||
|
#+begin_src nix
|
||||||
|
console.keyMap = cfg.keymap;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Truly Miscelaneous Config
|
||||||
|
First, some scripts are written with the assumption that some
|
||||||
|
utilities are always in the same place, such as =/bin/bash=. It is,
|
||||||
|
however, not always the case with NixOS. Mic92’s [[https://github.com/Mic92/envfs][envfs]] solves that.
|
||||||
|
#+name: envfs
|
||||||
|
#+begin_src nix
|
||||||
|
services.envfs.enable = true;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
I have no idea why, but sometimes, [[https://orca.gnome.org/][Orca]] get activated without my
|
||||||
|
consent. So I hard-disable it here.
|
||||||
|
#+name: orca
|
||||||
|
#+begin_src nix
|
||||||
|
services.orca.enable = false;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
I was surprised to see =/tmp= still hold the same files after my first
|
||||||
|
reboot in NixOS, I always assumed it was cleared on every reboot on
|
||||||
|
every system. But I can enable this behaviour back.
|
||||||
|
#+name: clean-tmp
|
||||||
|
#+begin_src nix
|
||||||
|
boot.tmp.cleanOnBoot = true;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Lastly, I want to make sure my shell completions work, so I’ll enable
|
||||||
|
this.
|
||||||
|
#+name: completion
|
||||||
|
#+begin_src nix
|
||||||
|
environment.pathsToLink = [
|
||||||
|
"/share/bash-completion"
|
||||||
|
"/share/zsh"
|
||||||
|
];
|
||||||
|
#+end_src
|
||||||
@@ -7,33 +7,49 @@
|
|||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.mySystem.networking;
|
cfg = config.mySystem.networking;
|
||||||
in {
|
in {
|
||||||
options.mySystem.networking = with types; {
|
options.mySystem.networking.hostname = mkOption {
|
||||||
hostname = mkOption {
|
type = types.str;
|
||||||
type = str;
|
|
||||||
example = "gampo";
|
example = "gampo";
|
||||||
};
|
};
|
||||||
id = mkOption {
|
config.networking.hostName = cfg.hostname;
|
||||||
type = str;
|
options.mySystem.networking.id = mkOption {
|
||||||
|
type = types.str;
|
||||||
example = "deadb33f";
|
example = "deadb33f";
|
||||||
};
|
};
|
||||||
domain = mkOption {
|
config.networking.hostId = cfg.id;
|
||||||
type = nullOr str;
|
options.mySystem.networking.domain = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
example = "phundrak.com";
|
example = "phundrak.com";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
hostFiles = mkOption {
|
config.networking.domain = cfg.domain;
|
||||||
type = listOf path;
|
options.mySystem.networking.hostFiles = mkOption {
|
||||||
|
type = types.listOf types.path;
|
||||||
example = [/path/to/hostFile];
|
example = [/path/to/hostFile];
|
||||||
default = [];
|
default = [];
|
||||||
};
|
};
|
||||||
firewall = {
|
config.networking.hostFiles = cfg.hostFiles;
|
||||||
openPorts = mkOption {
|
options.mySystem.networking.wifi.disablePowersave = mkEnableOption ''
|
||||||
type = listOf int;
|
Disables powersave for Wifi.
|
||||||
|
|
||||||
|
Used mainly for the PineTab2, as leaving WiFi powersave with the bes2600 can cause stability issues.
|
||||||
|
'';
|
||||||
|
config.networking.networkmanager = {
|
||||||
|
enable = true;
|
||||||
|
wifi.powersave = !cfg.wifi.disablePowersave;
|
||||||
|
};
|
||||||
|
options.mySystem.networking.firewall.openPorts = mkOption {
|
||||||
|
type = types.listOf types.int;
|
||||||
example = [22 80 443];
|
example = [22 80 443];
|
||||||
default = [];
|
default = [];
|
||||||
};
|
};
|
||||||
openPortRanges = mkOption {
|
config.networking.firewall = {
|
||||||
type = listOf (attrsOf port);
|
enable = true;
|
||||||
|
allowedTCPPorts = cfg.firewall.openPorts;
|
||||||
|
allowedUDPPorts = cfg.firewall.openPorts;
|
||||||
|
};
|
||||||
|
options.mySystem.networking.firewall.openPortRanges = mkOption {
|
||||||
|
type = types.listOf (types.attrsOf types.port);
|
||||||
default = [];
|
default = [];
|
||||||
example = [
|
example = [
|
||||||
{
|
{
|
||||||
@@ -46,35 +62,15 @@
|
|||||||
accepted.
|
accepted.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
extraCommands = mkOption {
|
config.networking.firewall = {
|
||||||
type = nullOr lines;
|
allowedTCPPortRanges = cfg.firewall.openPortRanges;
|
||||||
|
allowedUDPPortRanges = cfg.firewall.openPortRanges;
|
||||||
|
};
|
||||||
|
options.mySystem.networking.firewall.extraCommands = mkOption {
|
||||||
|
type = types.nullOr types.lines;
|
||||||
example = "iptables -A INPUTS -p icmp -j ACCEPT";
|
example = "iptables -A INPUTS -p icmp -j ACCEPT";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
};
|
config.networking.firewall.extraCommands = mkIf (cfg.firewall.extraCommands != null) cfg.firewall.extraCommands;
|
||||||
wifi.disablePowersave = mkEnableOption ''
|
|
||||||
Disables powersave for Wifi.
|
|
||||||
|
|
||||||
Used mainly for the PineTab2, as leaving WiFi powersave with the bes2600 can cause stability issues.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
config.networking = {
|
|
||||||
hostName = cfg.hostname; # Define your hostname.
|
|
||||||
hostId = cfg.id;
|
|
||||||
networkmanager = {
|
|
||||||
enable = true;
|
|
||||||
wifi.powersave = ! cfg.wifi.disablePowersave;
|
|
||||||
};
|
|
||||||
inherit (cfg) hostFiles domain;
|
|
||||||
firewall = {
|
|
||||||
enable = true;
|
|
||||||
allowedTCPPorts = cfg.firewall.openPorts;
|
|
||||||
allowedUDPPorts = cfg.firewall.openPorts;
|
|
||||||
allowedTCPPortRanges = cfg.firewall.openPortRanges;
|
|
||||||
allowedUDPPortRanges = cfg.firewall.openPortRanges;
|
|
||||||
extraCommands = (mkIf (cfg.firewall.extraCommands != null)) cfg.firewall.extraCommands;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
#+title: Networking
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* Networking
|
||||||
|
This module centralises the basic networking identity of a host —
|
||||||
|
hostname, host ID, domain, NetworkManager and the firewall — behind a
|
||||||
|
single =mySystem.networking= namespace. Here’s the skeleton of the
|
||||||
|
=nixos.networking= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{...}: {
|
||||||
|
flake.modules.nixos.networking = {
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib; let
|
||||||
|
cfg = config.mySystem.networking;
|
||||||
|
in {
|
||||||
|
<<hostname>>
|
||||||
|
<<host-id>>
|
||||||
|
<<domain>>
|
||||||
|
<<host-files>>
|
||||||
|
<<wifi-powersave>>
|
||||||
|
<<firewall-ports>>
|
||||||
|
<<firewall-port-ranges>>
|
||||||
|
<<firewall-extra-commands>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Hostname
|
||||||
|
#+name: hostname
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.networking.hostname = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "gampo";
|
||||||
|
};
|
||||||
|
config.networking.hostName = cfg.hostname;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Host ID
|
||||||
|
Every host needs a unique =hostId=; besides identifying the machine on
|
||||||
|
the network, ZFS also uses it to guard against accidentally importing
|
||||||
|
a pool that’s still active on another machine (see [[file:../boot/zfs.org][ZFS Support]]).
|
||||||
|
#+name: host-id
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.networking.id = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "deadb33f";
|
||||||
|
};
|
||||||
|
config.networking.hostId = cfg.id;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Domain
|
||||||
|
Not every host needs a domain name, so this defaults to =null=.
|
||||||
|
#+name: domain
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.networking.domain = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
example = "phundrak.com";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
config.networking.domain = cfg.domain;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Extra Host Files
|
||||||
|
=hostFiles= lets a host point at extra files to merge into =/etc/hosts=,
|
||||||
|
on top of whatever NixOS generates itself.
|
||||||
|
#+name: host-files
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.networking.hostFiles = mkOption {
|
||||||
|
type = types.listOf types.path;
|
||||||
|
example = [/path/to/hostFile];
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
config.networking.hostFiles = cfg.hostFiles;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** NetworkManager and WiFi Powersave
|
||||||
|
NetworkManager is always enabled; the only thing a host can tune here
|
||||||
|
is WiFi powersave. I mainly need to turn it off on the PineTab2, since
|
||||||
|
leaving powersave on with its =bes2600= WiFi chip causes stability
|
||||||
|
issues.
|
||||||
|
#+name: wifi-powersave
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.networking.wifi.disablePowersave = mkEnableOption ''
|
||||||
|
Disables powersave for Wifi.
|
||||||
|
|
||||||
|
Used mainly for the PineTab2, as leaving WiFi powersave with the bes2600 can cause stability issues.
|
||||||
|
'';
|
||||||
|
config.networking.networkmanager = {
|
||||||
|
enable = true;
|
||||||
|
wifi.powersave = !cfg.wifi.disablePowersave;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Firewall: Ports
|
||||||
|
This also turns the firewall itself on; =openPorts= is just the plain
|
||||||
|
list of single ports to open, on both TCP and UDP.
|
||||||
|
#+name: firewall-ports
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.networking.firewall.openPorts = mkOption {
|
||||||
|
type = types.listOf types.int;
|
||||||
|
example = [22 80 443];
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
config.networking.firewall = {
|
||||||
|
enable = true;
|
||||||
|
allowedTCPPorts = cfg.firewall.openPorts;
|
||||||
|
allowedUDPPorts = cfg.firewall.openPorts;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Firewall: Port Ranges
|
||||||
|
=openPortRanges= does the same, but for a contiguous range of ports at
|
||||||
|
once, again on both TCP and UDP.
|
||||||
|
#+name: firewall-port-ranges
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.networking.firewall.openPortRanges = mkOption {
|
||||||
|
type = types.listOf (types.attrsOf types.port);
|
||||||
|
default = [];
|
||||||
|
example = [
|
||||||
|
{
|
||||||
|
from = 8080;
|
||||||
|
to = 8082;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
description = ''
|
||||||
|
A range of TCP and UDP ports on which incoming connections are
|
||||||
|
accepted.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
config.networking.firewall = {
|
||||||
|
allowedTCPPortRanges = cfg.firewall.openPortRanges;
|
||||||
|
allowedUDPPortRanges = cfg.firewall.openPortRanges;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Firewall: Extra Commands
|
||||||
|
For anything the declarative options above can’t express, =extraCommands=
|
||||||
|
lets a host drop raw =iptables= commands straight into the firewall
|
||||||
|
setup.
|
||||||
|
#+name: firewall-extra-commands
|
||||||
|
#+begin_src nix
|
||||||
|
options.mySystem.networking.firewall.extraCommands = mkOption {
|
||||||
|
type = types.nullOr types.lines;
|
||||||
|
example = "iptables -A INPUTS -p icmp -j ACCEPT";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
config.networking.firewall.extraCommands = mkIf (cfg.firewall.extraCommands != null) cfg.firewall.extraCommands;
|
||||||
|
#+end_src
|
||||||
@@ -1,20 +1,7 @@
|
|||||||
{...}: {
|
{
|
||||||
flake.modules.nixos.tailscale = {
|
flake.modules.nixos.tailscale = {
|
||||||
lib,
|
services.tailscale = {
|
||||||
config,
|
enable = true;
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.mySystem.network.tailscale;
|
|
||||||
in {
|
|
||||||
options.mySystem.network.tailscale = {
|
|
||||||
enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config.services.tailscale = {
|
|
||||||
inherit (cfg) enable;
|
|
||||||
extraSetFlags = [
|
extraSetFlags = [
|
||||||
"--accept-dns"
|
"--accept-dns"
|
||||||
"--accept-routes"
|
"--accept-routes"
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#+title: Tailscale
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* Tailscale
|
||||||
|
I use [[https://tailscale.com/][Tailscale]] as the mesh VPN tying all my machines together. Here’s
|
||||||
|
the =nixos.tailscale= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.tailscale = {
|
||||||
|
services.tailscale = {
|
||||||
|
<<enable>>
|
||||||
|
<<extra-flags>>
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Enabling Tailscale
|
||||||
|
#+name: enable
|
||||||
|
#+begin_src nix
|
||||||
|
enable = true;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Extra Flags
|
||||||
|
I add some extra flags for Tailscale.
|
||||||
|
|
||||||
|
#+name: flags
|
||||||
|
| Flag | Why |
|
||||||
|
|-----------------+---------------------------------------------------------|
|
||||||
|
| =--accept-dns= | Turns on MagicDNS |
|
||||||
|
| =--accept-routes= | Let this machine use subnets advertised by other nodes |
|
||||||
|
| =--ssh= | Turns on Tailscale’s own SSH server for easy SSH access |
|
||||||
|
|
||||||
|
#+name: make-flags
|
||||||
|
#+begin_src emacs-lisp :exports none :var flags=flags :cache yes
|
||||||
|
(mapconcat (lambda (flag)
|
||||||
|
(replace-regexp-in-string "=" "\"" (car flag)))
|
||||||
|
flags
|
||||||
|
"\n")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[4969e8a817fa6617e136b57d47a43d6e21ce2a7b]: make-flags
|
||||||
|
: "--accept-dns"
|
||||||
|
: "--accept-routes"
|
||||||
|
: "--ssh"
|
||||||
|
|
||||||
|
#+name: extra-flags
|
||||||
|
#+begin_src nix
|
||||||
|
extraSetFlags = [
|
||||||
|
<<make-flags()>>
|
||||||
|
];
|
||||||
|
#+end_src
|
||||||
+12
-18
@@ -1,5 +1,5 @@
|
|||||||
{...}: let
|
let
|
||||||
cacheSettings = {
|
cacheSettings = rec {
|
||||||
substituters = [
|
substituters = [
|
||||||
"https://phundrak.cachix.org?priority=10"
|
"https://phundrak.cachix.org?priority=10"
|
||||||
"https://nix-community.cachix.org?priority=20"
|
"https://nix-community.cachix.org?priority=20"
|
||||||
@@ -10,28 +10,22 @@
|
|||||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||||
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
||||||
];
|
];
|
||||||
|
commonConf = {
|
||||||
|
extra-trusted-public-keys = trustedPublicKeys;
|
||||||
|
extra-substituters = substituters;
|
||||||
|
extra-experimental-features = ["nix-command" "flakes"];
|
||||||
|
http-connections = 128;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
flake-file.nixConfig = {
|
flake-file.nixConfig = cacheSettings.commonConf;
|
||||||
extra-trusted-public-keys = cacheSettings.trustedPublicKeys;
|
flake.nixConfig = cacheSettings.commonConf;
|
||||||
extra-substituters = cacheSettings.substituters;
|
|
||||||
extra-experimental-features = ["nix-command" "flakes"];
|
|
||||||
http-connections = 128;
|
|
||||||
};
|
|
||||||
|
|
||||||
flake.nixConfig = {
|
|
||||||
extra-trusted-public-keys = cacheSettings.trustedPublicKeys;
|
|
||||||
extra-substituters = cacheSettings.substituters;
|
|
||||||
extra-experimental-features = ["nix-command" "flakes"];
|
|
||||||
http-connections = 128;
|
|
||||||
};
|
|
||||||
|
|
||||||
flake.modules.nixos.nix-cache-settings = {
|
flake.modules.nixos.nix-cache-settings = {
|
||||||
nix.settings = {
|
nix.settings = {
|
||||||
substituters = cacheSettings.substituters;
|
inherit (cacheSettings) substituters;
|
||||||
trusted-public-keys = cacheSettings.trustedPublicKeys;
|
trusted-public-keys = cacheSettings.trustedPublicKeys;
|
||||||
http-connections = 128;
|
|
||||||
experimental-features = ["nix-command" "flakes"];
|
experimental-features = ["nix-command" "flakes"];
|
||||||
|
http-connections = 128;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#+title: Nix Configuration
|
||||||
|
#+setupfile: headers
|
||||||
|
#+property: header-args:emacs-lisp :lexical t :exports none :tangle no
|
||||||
|
|
||||||
|
* Nix Configuration
|
||||||
|
Something that I want to enable everywhere is, first and foremost, the
|
||||||
|
support for Nix commands and Nix flakes. I also want to make sure I
|
||||||
|
can use some caches, also known as substituters, including one of mine
|
||||||
|
from Cachix, to avoid compiling stuff as much as possible.
|
||||||
|
|
||||||
|
So first, here are my caches with their public key.
|
||||||
|
|
||||||
|
#+name: substituters
|
||||||
|
| Substituter's URL | Public Key |
|
||||||
|
|----------------------------------------------+-------------------------------------------------------------------------|
|
||||||
|
| https://phundrak.cachix.org?priority=10 | =phundrak.cachix.org-1:osJAkYO0ioTOPqaQCIXMfIRz1/+YYlVFkup3R2KSexk== |
|
||||||
|
| https://nix-community.cachix.org?priority=20 | =nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs== |
|
||||||
|
| https://cache.nixos.org?priority=40 | =cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY== |
|
||||||
|
|
||||||
|
#+name: substituters-urls
|
||||||
|
#+begin_src emacs-lisp :var subs=substituters :cache yes
|
||||||
|
(mapconcat (lambda (sub) (format "\"%s\"" (car sub))) subs "\n")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[99d05698d7e8ca90b34823f4dd4858224be8d007]: substituters-urls
|
||||||
|
: "https://phundrak.cachix.org?priority=10"
|
||||||
|
: "https://nix-community.cachix.org?priority=20"
|
||||||
|
: "https://cache.nixos.org?priority=40"
|
||||||
|
|
||||||
|
#+name: substituters-keys
|
||||||
|
#+begin_src emacs-lisp :var subs=substituters :cache yes
|
||||||
|
(require 's)
|
||||||
|
(mapconcat (lambda (sub) (format "\"%s\""
|
||||||
|
(s-chop-prefix "=" (s-chop-suffix "=" (cadr sub)))))
|
||||||
|
subs
|
||||||
|
"\n")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[6f5e709a7b1c1dd55e4187dfaf8be945138c68ec]: substituters-keys
|
||||||
|
: "phundrak.cachix.org-1:osJAkYO0ioTOPqaQCIXMfIRz1/+YYlVFkup3R2KSexk="
|
||||||
|
: "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||||
|
: "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
||||||
|
|
||||||
|
This results in the following substituters and trusted public keys.
|
||||||
|
#+name: config-vars
|
||||||
|
#+begin_src nix :noweb yes
|
||||||
|
substituters = [
|
||||||
|
<<substituters-urls()>>
|
||||||
|
];
|
||||||
|
trustedPublicKeys = [
|
||||||
|
<<substituters-keys()>>
|
||||||
|
];
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Now, we can declare the rest of the file. You’ll see, it repeats
|
||||||
|
itself a bit.
|
||||||
|
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
let
|
||||||
|
cacheSettings = rec {
|
||||||
|
<<config-vars>>
|
||||||
|
commonConf = {
|
||||||
|
extra-trusted-public-keys = trustedPublicKeys;
|
||||||
|
extra-substituters = substituters;
|
||||||
|
extra-experimental-features = ["nix-command" "flakes"];
|
||||||
|
http-connections = 128;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
flake-file.nixConfig = cacheSettings.commonConf;
|
||||||
|
flake.nixConfig = cacheSettings.commonConf;
|
||||||
|
flake.modules.nixos.nix-cache-settings = {
|
||||||
|
nix.settings = {
|
||||||
|
inherit (cacheSettings) substituters;
|
||||||
|
trusted-public-keys = cacheSettings.trustedPublicKeys;
|
||||||
|
experimental-features = ["nix-command" "flakes"];
|
||||||
|
http-connections = 128;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
@@ -1,15 +1,7 @@
|
|||||||
{
|
{
|
||||||
flake.modules.nixos.appimage = {
|
flake.modules.nixos.appimage = {
|
||||||
lib,
|
programs.appimage = {
|
||||||
config,
|
enable = true;
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.mySystem.packages.appimage;
|
|
||||||
in {
|
|
||||||
options.mySystem.packages.appimage.enable = mkEnableOption "Enables AppImage support";
|
|
||||||
config.programs.appimage = mkIf cfg.enable {
|
|
||||||
inherit (cfg) enable;
|
|
||||||
binfmt = true;
|
binfmt = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#+title: AppImage
|
||||||
|
#+setupfile: ../headers
|
||||||
|
|
||||||
|
* AppImage
|
||||||
|
A small module to let AppImages run directly, without having to
|
||||||
|
extract or wrap them by hand first. Here’s the =nixos.appimage= module.
|
||||||
|
#+begin_src nix :tangle yes
|
||||||
|
{
|
||||||
|
flake.modules.nixos.appimage = {
|
||||||
|
<<enable-appimage>>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
=binfmt= registers AppImages with the kernel’s =binfmt_misc=, so running
|
||||||
|
one is as simple as executing it directly, the same as any other
|
||||||
|
binary.
|
||||||
|
#+name: enable-appimage
|
||||||
|
#+begin_src nix
|
||||||
|
programs.appimage = {
|
||||||
|
enable = true;
|
||||||
|
binfmt = true;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -8,11 +8,8 @@
|
|||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.mySystem.packages.flatpak;
|
cfg = config.mySystem.packages.flatpak;
|
||||||
in {
|
in {
|
||||||
options.mySystem.packages.flatpak = {
|
options.mySystem.packages.flatpak.builder.enable = mkEnableOption "Enable Flatpak builder";
|
||||||
enable = mkEnableOption "Enable Flatpak support";
|
config = {
|
||||||
builder.enable = mkEnableOption "Enable Flatpak builder";
|
|
||||||
};
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
environment.systemPackages = lists.optional cfg.builder.enable pkgs.flatpak-builder;
|
environment.systemPackages = lists.optional cfg.builder.enable pkgs.flatpak-builder;
|
||||||
services.flatpak.enable = true;
|
services.flatpak.enable = true;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user