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:
2026-10-04 22:34:28 +02:00
parent 5f4a7a4a42
commit a2b21feacc
13 changed files with 898 additions and 86 deletions
+17
View File
@@ -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.
+21 -39
View File
@@ -1,44 +1,26 @@
{
flake.modules.nixos.hardened = {
lib,
config,
...
}:
with lib; let
cfg = config.mySystem.boot.kernel;
in {
options.mySystem.boot.kernel.hardened = mkEnableOption "Enables hardened Linux kernel";
config.boot = {
kernelModules = lists.optional cfg.hardened "tcp_bbr";
kernel.sysctl = mkIf cfg.hardened {
"kernel.sysrq" = 0; # Disable magic SysRq key
# Ignore ICMP broadcasts to avoid participating in Smurf attacks
"net.ipv4.icmp_echo_ignore_broadcasts" = 1;
# Ignore bad ICMP errors
"net.ipv4.icmp_ignore_bogus_error_responses" = 1;
# SYN flood protection
"net.ipv4.tcp_syncookies" = 1;
# Do not accept ICMP redirects (prevent MITM attacks)
"net.ipv4.conf.all.accept_redirects" = 0;
"net.ipv4.conf.default_accept_redirects" = 0;
"net.ipv4.conf.all.secure_redirects" = 0;
"net.ipv4.conf.default.secure_redirects" = 0;
"net.ipv6.conf.all.accept_redirects" = 0;
"net.ipv6.conf.default.accept_redirects" = 0;
# Do not send ICMP redirects (we are not a router)
"net.ipv4.conf.all.send_redirects" = 0;
# Do not accept IP source route packets (we are not a router)
"net.ipv4.conf.all.accept_source_route" = 0;
"net.ipv6.conf.all.accept_source_route" = 0;
# Protect against tcp time-wait assassination hazards
"net.ipv4.tcp_rfc1337" = 1;
# Latency reduction
"net.ipv4.tcp_fastopen" = 3;
# Bufferfloat mitigations
"net.ipv4.tcp_congestion_control" = "bbr";
"net.core.default_qdisc" = "cake";
};
boot = {
kernelModules = ["tcp_bbr"];
kernel.sysctl = {
"kernel.sysrq" = 0;
"net.ipv4.icmp_echo_ignore_broadcasts" = 1;
"net.ipv4.icmp_ignore_bogus_error_responses" = 1;
"net.ipv4.conf.all.accept_redirects" = 0;
"net.ipv4.conf.default_accept_redirects" = 0;
"net.ipv4.conf.all.secure_redirects" = 0;
"net.ipv4.conf.default.secure_redirects" = 0;
"net.ipv6.conf.all.accept_redirects" = 0;
"net.ipv6.conf.default.accept_redirects" = 0;
"net.ipv4.conf.all.send_redirects" = 0;
"net.ipv4.conf.all.accept_source_route" = 0;
"net.ipv6.conf.all.accept_source_route" = 0;
"net.ipv4.tcp_syncookies" = 1;
"net.ipv4.tcp_rfc1337" = 1;
"net.ipv4.tcp_congestion_control" = "bbr";
"net.core.default_qdisc" = "cake";
"net.ipv4.tcp_fastopen" = 3;
};
};
};
}
+116
View File
@@ -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!
+74
View File
@@ -0,0 +1,74 @@
#+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, and some use ZFS.
All that gets exposed with my module =nixos.loader=.
#+begin_src nix :tangle loader.new.nix
{
flake.modules.nixos.loader = {
lib,
config,
...
}:
with lib; let
cfg = config.mySystem.boot;
in {
};
}
#+end_src
** Bootloaders
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";
default = "";
};
};
#+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
** ZFS
Now, this is where I enable
+7 -11
View File
@@ -25,7 +25,6 @@
inputs.nixpkgsUnstable.follows = "nixpkgsPinetab2Kernel";
};
};
systems = ["x86_64-linux" "aarch64-linux"];
flake.lib = {
@@ -37,7 +36,6 @@
];
};
};
mkHome = system: userName: hostName: {
"${userName}@${hostName}" = inputs.home-manager.lib.homeManagerConfiguration {
pkgs = inputs.nixpkgs.legacyPackages.${system};
@@ -48,7 +46,6 @@
modules = [config.flake.modules.homeManager."${userName}-${hostName}"];
};
};
mkPinetab = buildPlatform: variantModule: {
pinetab2 = inputs.nixpkgs.lib.nixosSystem {
system = "aarch64-linux";
@@ -72,24 +69,23 @@
};
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" "NaroMk3")
(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")
(config.flake.lib.mkPinetab "x86_64-linux" config.flake.modules.nixos.pinetab2-gnome)
];
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" "NaroMk3")
(config.flake.lib.mkHome "x86_64-linux" "phundrak" "pinetab2")
(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")
];
perSystem = {
pkgs,
system,
+22
View File
@@ -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>@@
+343
View File
@@ -0,0 +1,343 @@
#+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 to have [[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 posibility 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
View File
@@ -11,5 +11,5 @@
};
};
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";
}
+82
View File
@@ -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
+12 -16
View File
@@ -7,31 +7,27 @@
with lib; let
cfg = config.mySystem.misc;
in {
options.mySystem.misc = {
timezone = mkOption {
type = types.str;
default = "Europe/Paris";
};
keymap = mkOption {
type = types.str;
default = "fr";
example = "fr-bepo";
description = "Keymap to use in the TTY console";
};
options.mySystem.misc.timezone = mkOption {
type = types.str;
default = "Europe/Paris";
};
options.mySystem.misc.keymap = mkOption {
type = types.str;
default = "fr";
example = "fr-bepo";
description = "Keymap to use in the TTY console";
};
config = {
boot.tmp.cleanOnBoot = true;
console.keyMap = cfg.keymap;
time.timeZone = cfg.timezone;
services.envfs.enable = true;
services.orca.enable = false;
boot.tmp.cleanOnBoot = true;
environment.pathsToLink = [
"/share/bash-completion"
"/share/zsh"
];
services = {
orca.enable = false;
envfs.enable = true;
};
};
};
}
+109
View File
@@ -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
+12 -18
View File
@@ -1,5 +1,5 @@
{...}: let
cacheSettings = {
let
cacheSettings = rec {
substituters = [
"https://phundrak.cachix.org?priority=10"
"https://nix-community.cachix.org?priority=20"
@@ -10,28 +10,22 @@
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
];
commonConf = {
extra-trusted-public-keys = trustedPublicKeys;
extra-substituters = substituters;
extra-experimental-features = ["nix-command" "flakes"];
http-connections = 128;
};
};
in {
flake-file.nixConfig = {
extra-trusted-public-keys = cacheSettings.trustedPublicKeys;
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-file.nixConfig = cacheSettings;
flake.nixConfig = cacheSettings;
flake.modules.nixos.nix-cache-settings = {
nix.settings = {
substituters = cacheSettings.substituters;
inherit (cacheSettings) substituters;
trusted-public-keys = cacheSettings.trustedPublicKeys;
http-connections = 128;
experimental-features = ["nix-command" "flakes"];
http-connections = 128;
};
};
}
+81
View File
@@ -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;
flake.nixConfig = cacheSettings;
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