From b0d6795c9f1d9a74e87b2b05f94a71130d8f2380 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 12:13:59 +0100 Subject: [PATCH 01/29] Add script to generate options documentation This necessitated a little refactoring, splitting the options declarations out of the config so that I don't need to somehow evaluate all the standard nixos modules just to generate documentation for my stuff. For now, the script treats missing documentation as a warning, not an error. Once everything is documented, this will change. --- flake.nix | 37 +++++++++++++++ scripts/lint.sh | 10 ++++ shared/backups/default.nix | 22 ++------- shared/backups/options.nix | 25 ++++++++++ shared/bookdb/default.nix | 15 ++---- shared/bookdb/options.nix | 15 ++++++ shared/bookmarks/default.nix | 12 ++--- shared/bookmarks/options.nix | 15 ++++++ shared/concourse/default.nix | 13 ++---- shared/concourse/options.nix | 16 +++++++ shared/default.nix | 6 +-- shared/erase-your-darlings/default.nix | 10 ++-- shared/erase-your-darlings/options.nix | 13 ++++++ shared/finder/default.nix | 10 ++-- shared/finder/options.nix | 13 ++++++ shared/foundryvtt/default.nix | 11 ++--- shared/foundryvtt/options.nix | 11 +++++ shared/minecraft/default.nix | 30 +++--------- shared/minecraft/options.nix | 24 ++++++++++ shared/oci-containers/default.nix | 61 ++---------------------- shared/oci-containers/options.nix | 64 ++++++++++++++++++++++++++ shared/options.nix | 9 ++++ shared/pleroma/default.nix | 22 +++------ shared/pleroma/options.nix | 18 ++++++++ shared/resolved/default.nix | 17 ++----- shared/resolved/options.nix | 20 ++++++++ shared/rtorrent/default.nix | 22 ++------- shared/rtorrent/options.nix | 22 +++++++++ shared/umami/default.nix | 10 ++-- shared/umami/options.nix | 13 ++++++ 30 files changed, 376 insertions(+), 210 deletions(-) create mode 100644 shared/backups/options.nix create mode 100644 shared/bookdb/options.nix create mode 100644 shared/bookmarks/options.nix create mode 100644 shared/concourse/options.nix create mode 100644 shared/erase-your-darlings/options.nix create mode 100644 shared/finder/options.nix create mode 100644 shared/foundryvtt/options.nix create mode 100644 shared/minecraft/options.nix create mode 100644 shared/oci-containers/options.nix create mode 100644 shared/options.nix create mode 100644 shared/pleroma/options.nix create mode 100644 shared/resolved/options.nix create mode 100644 shared/rtorrent/options.nix create mode 100644 shared/umami/options.nix diff --git a/flake.nix b/flake.nix index 9a461d1e..b42d0ea5 100644 --- a/flake.nix +++ b/flake.nix @@ -88,6 +88,43 @@ ${pkgs.lib.fileContents ./scripts/secrets.sh} ''; + + option-docs = + let + eval = pkgs.lib.evalModules { + modules = [ + { config._module.args = { inherit pkgs; }; } + ./shared/options.nix + ./shared/bookmarks/options.nix + ./shared/umami/options.nix + ./shared/concourse/options.nix + ./shared/rtorrent/options.nix + ./shared/oci-containers/options.nix + ./shared/pleroma/options.nix + ./shared/resolved/options.nix + ./shared/bookdb/options.nix + ./shared/minecraft/options.nix + ./shared/erase-your-darlings/options.nix + ./shared/backups/options.nix + ./shared/foundryvtt/options.nix + ./shared/finder/options.nix + ]; + }; + optionsDoc = pkgs.nixosOptionsDoc { + options = eval.options; + warningsAreErrors = false; + }; + in + mkApp "options-json" '' + case "$1" in + "json") + cat ${optionsDoc.optionsJSON}/share/doc/nixos/options.json + ;; + *) + cat ${optionsDoc.optionsCommonMark} + ;; + esac + ''; }; }; } diff --git a/scripts/lint.sh b/scripts/lint.sh index 80b74ea7..9c2c26bc 100644 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -10,6 +10,16 @@ find . -name '*.sh' -print0 | xargs -0 -n1 shellcheck -s bash -e SC2001 # E731: assign lambda to a variable find . -name '*.py' -print0 | xargs -0 -n1 flake8 --ignore=E501,E731 +find . -name options.nix -print0 | while IFS= read -r -d '' filename; do + if ! grep -q "$filename" flake.nix; then + exit 1 + fi +done + +if git grep 'options.nixfiles' | grep -vE 'options.nix'; then + exit 1 +fi + if git grep 'callPackage' | grep -vE 'flake.nix'; then exit 1 fi diff --git a/shared/backups/default.nix b/shared/backups/default.nix index 949408b8..1539bf9f 100644 --- a/shared/backups/default.nix +++ b/shared/backups/default.nix @@ -75,25 +75,9 @@ let }; in { - options.nixfiles.backups = { - enable = mkOption { type = types.bool; default = false; }; - scripts = mkOption { type = types.attrsOf types.str; default = { }; }; - pythonScripts = mkOption { type = types.attrsOf types.str; default = { }; }; - sudoRules = mkOption { - type = types.listOf (types.submodule { - options = { - command = mkOption { type = types.str; }; - runAs = mkOption { type = types.str; default = "ALL:ALL"; }; - }; - }); - default = { }; - }; - environmentFile = mkOption { type = types.str; }; - onCalendarFull = mkOption { type = types.str; default = "monthly"; }; - onCalendarIncr = mkOption { type = types.str; default = "Mon, 04:00"; }; - user = mkOption { type = types.str; default = "barrucadu"; }; - group = mkOption { type = types.str; default = "users"; }; - }; + imports = [ + ./options.nix + ]; config = mkIf cfg.enable { systemd.services.backup-scripts-full = { diff --git a/shared/backups/options.nix b/shared/backups/options.nix new file mode 100644 index 00000000..b636721c --- /dev/null +++ b/shared/backups/options.nix @@ -0,0 +1,25 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.backups = { + enable = mkOption { type = types.bool; default = false; }; + scripts = mkOption { type = types.attrsOf types.str; default = { }; }; + pythonScripts = mkOption { type = types.attrsOf types.str; default = { }; }; + sudoRules = mkOption { + type = types.listOf (types.submodule { + options = { + command = mkOption { type = types.str; }; + runAs = mkOption { type = types.str; default = "ALL:ALL"; }; + }; + }); + default = { }; + }; + environmentFile = mkOption { type = types.str; }; + onCalendarFull = mkOption { type = types.str; default = "monthly"; }; + onCalendarIncr = mkOption { type = types.str; default = "Mon, 04:00"; }; + user = mkOption { type = types.str; default = "barrucadu"; }; + group = mkOption { type = types.str; default = "users"; }; + }; +} diff --git a/shared/bookdb/default.nix b/shared/bookdb/default.nix index 750bec33..ad5baa8c 100644 --- a/shared/bookdb/default.nix +++ b/shared/bookdb/default.nix @@ -6,17 +6,10 @@ let backend = config.nixfiles.oci-containers.backend; in { - imports = [ ./erase-your-darlings.nix ]; - - options.nixfiles.bookdb = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 46667; }; - esPort = mkOption { type = types.int; default = 47164; }; - esTag = mkOption { type = types.str; default = "8.0.0"; }; - baseURI = mkOption { type = types.str; }; - readOnly = mkOption { type = types.bool; default = false; }; - dataDir = mkOption { type = types.str; default = "/srv/bookdb"; }; - }; + imports = [ + ./erase-your-darlings.nix + ./options.nix + ]; config = mkIf cfg.enable { systemd.services.bookdb = { diff --git a/shared/bookdb/options.nix b/shared/bookdb/options.nix new file mode 100644 index 00000000..f93565f2 --- /dev/null +++ b/shared/bookdb/options.nix @@ -0,0 +1,15 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.bookdb = { + enable = mkOption { type = types.bool; default = false; }; + port = mkOption { type = types.int; default = 46667; }; + esPort = mkOption { type = types.int; default = 47164; }; + esTag = mkOption { type = types.str; default = "8.0.0"; }; + baseURI = mkOption { type = types.str; }; + readOnly = mkOption { type = types.bool; default = false; }; + dataDir = mkOption { type = types.str; default = "/srv/bookdb"; }; + }; +} diff --git a/shared/bookmarks/default.nix b/shared/bookmarks/default.nix index 6bf729ff..ffad848b 100644 --- a/shared/bookmarks/default.nix +++ b/shared/bookmarks/default.nix @@ -6,15 +6,9 @@ let backend = config.nixfiles.oci-containers.backend; in { - options.nixfiles.bookmarks = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 48372; }; - esPort = mkOption { type = types.int; default = 43389; }; - esTag = mkOption { type = types.str; default = "8.0.0"; }; - baseURI = mkOption { type = types.str; }; - readOnly = mkOption { type = types.bool; default = false; }; - environmentFile = mkOption { type = types.nullOr types.str; default = null; }; - }; + imports = [ + ./options.nix + ]; config = mkIf cfg.enable { systemd.services.bookmarks = { diff --git a/shared/bookmarks/options.nix b/shared/bookmarks/options.nix new file mode 100644 index 00000000..670bb2d5 --- /dev/null +++ b/shared/bookmarks/options.nix @@ -0,0 +1,15 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.bookmarks = { + enable = mkOption { type = types.bool; default = false; }; + port = mkOption { type = types.int; default = 48372; }; + esPort = mkOption { type = types.int; default = 43389; }; + esTag = mkOption { type = types.str; default = "8.0.0"; }; + baseURI = mkOption { type = types.str; }; + readOnly = mkOption { type = types.bool; default = false; }; + environmentFile = mkOption { type = types.nullOr types.str; default = null; }; + }; +} diff --git a/shared/concourse/default.nix b/shared/concourse/default.nix index 0616c9ff..7d8e8bab 100644 --- a/shared/concourse/default.nix +++ b/shared/concourse/default.nix @@ -6,16 +6,9 @@ let backend = config.nixfiles.oci-containers.backend; in { - options.nixfiles.concourse = { - enable = mkOption { type = types.bool; default = false; }; - concourseTag = mkOption { type = types.str; default = "7.8.2"; }; - githubUser = mkOption { type = types.str; default = "barrucadu"; }; - port = mkOption { type = types.int; default = 46498; }; - metricsPort = mkOption { type = types.int; default = 45811; }; - postgresTag = mkOption { type = types.str; default = "13"; }; - workerScratchDir = mkOption { type = types.nullOr types.path; default = null; }; - environmentFile = mkOption { type = types.str; }; - }; + imports = [ + ./options.nix + ]; config = mkIf cfg.enable { # https://github.com/concourse/concourse/discussions/6529 diff --git a/shared/concourse/options.nix b/shared/concourse/options.nix new file mode 100644 index 00000000..340d5172 --- /dev/null +++ b/shared/concourse/options.nix @@ -0,0 +1,16 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.concourse = { + enable = mkOption { type = types.bool; default = false; }; + concourseTag = mkOption { type = types.str; default = "7.8.2"; }; + githubUser = mkOption { type = types.str; default = "barrucadu"; }; + port = mkOption { type = types.int; default = 46498; }; + metricsPort = mkOption { type = types.int; default = 45811; }; + postgresTag = mkOption { type = types.str; default = "13"; }; + workerScratchDir = mkOption { type = types.nullOr types.path; default = null; }; + environmentFile = mkOption { type = types.str; }; + }; +} diff --git a/shared/default.nix b/shared/default.nix index 5724aaaf..f6378564 100644 --- a/shared/default.nix +++ b/shared/default.nix @@ -18,6 +18,8 @@ let in { imports = [ + ./options.nix + # modules ./backups ./bookdb ./bookmarks @@ -33,10 +35,6 @@ in ./umami ]; - options.nixfiles.firewall = { - ipBlocklistFile = mkOption { type = types.nullOr types.str; default = null; }; - }; - config = { ############################################################################# ## General diff --git a/shared/erase-your-darlings/default.nix b/shared/erase-your-darlings/default.nix index add61faa..b77d2ac8 100644 --- a/shared/erase-your-darlings/default.nix +++ b/shared/erase-your-darlings/default.nix @@ -6,13 +6,9 @@ let cfg = config.nixfiles.eraseYourDarlings; in { - options.nixfiles.eraseYourDarlings = { - enable = mkOption { type = types.bool; default = false; }; - barrucaduPasswordFile = mkOption { type = types.str; }; - rootSnapshot = mkOption { type = types.str; default = "local/volatile/root@blank"; }; - persistDir = mkOption { type = types.path; default = "/persist"; }; - machineId = mkOption { type = types.str; }; - }; + imports = [ + ./options.nix + ]; config = mkIf cfg.enable { # Wipe / on boot diff --git a/shared/erase-your-darlings/options.nix b/shared/erase-your-darlings/options.nix new file mode 100644 index 00000000..b4fdeee5 --- /dev/null +++ b/shared/erase-your-darlings/options.nix @@ -0,0 +1,13 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.eraseYourDarlings = { + enable = mkOption { type = types.bool; default = false; }; + barrucaduPasswordFile = mkOption { type = types.str; }; + rootSnapshot = mkOption { type = types.str; default = "local/volatile/root@blank"; }; + persistDir = mkOption { type = types.path; default = "/persist"; }; + machineId = mkOption { type = types.str; }; + }; +} diff --git a/shared/finder/default.nix b/shared/finder/default.nix index 4813cf4a..ba85389d 100644 --- a/shared/finder/default.nix +++ b/shared/finder/default.nix @@ -5,13 +5,9 @@ let cfg = config.nixfiles.finder; in { - options.nixfiles.finder = { - enable = mkOption { type = types.bool; default = false; }; - image = mkOption { type = types.str; }; - port = mkOption { type = types.int; default = 44986; }; - esTag = mkOption { type = types.str; default = "8.0.0"; }; - mangaDir = mkOption { type = types.path; }; - }; + imports = [ + ./options.nix + ]; config = mkIf cfg.enable { nixfiles.oci-containers.pods.finder = { diff --git a/shared/finder/options.nix b/shared/finder/options.nix new file mode 100644 index 00000000..8dc07a2e --- /dev/null +++ b/shared/finder/options.nix @@ -0,0 +1,13 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.finder = { + enable = mkOption { type = types.bool; default = false; }; + image = mkOption { type = types.str; }; + port = mkOption { type = types.int; default = 44986; }; + esTag = mkOption { type = types.str; default = "8.0.0"; }; + mangaDir = mkOption { type = types.path; }; + }; +} diff --git a/shared/foundryvtt/default.nix b/shared/foundryvtt/default.nix index ca7323e2..32a58b2a 100644 --- a/shared/foundryvtt/default.nix +++ b/shared/foundryvtt/default.nix @@ -8,13 +8,10 @@ let cfg = config.nixfiles.foundryvtt; in { - imports = [ ./erase-your-darlings.nix ]; - - options.nixfiles.foundryvtt = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 46885; }; - dataDir = mkOption { type = types.str; default = "/var/lib/foundryvtt"; }; - }; + imports = [ + ./erase-your-darlings.nix + ./options.nix + ]; config = mkIf cfg.enable { systemd.services.foundryvtt = { diff --git a/shared/foundryvtt/options.nix b/shared/foundryvtt/options.nix new file mode 100644 index 00000000..18901369 --- /dev/null +++ b/shared/foundryvtt/options.nix @@ -0,0 +1,11 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.foundryvtt = { + enable = mkOption { type = types.bool; default = false; }; + port = mkOption { type = types.int; default = 46885; }; + dataDir = mkOption { type = types.str; default = "/var/lib/foundryvtt"; }; + }; +} diff --git a/shared/minecraft/default.nix b/shared/minecraft/default.nix index b06e2bc2..544239bb 100644 --- a/shared/minecraft/default.nix +++ b/shared/minecraft/default.nix @@ -1,3 +1,6 @@ +# Yes I know there's a NixOS minecraft module but it uses the Minecraft in +# nixpkgs whereas I want to run modded servers and packaging one is a pain. + { config, lib, pkgs, ... }: with lib; @@ -7,29 +10,10 @@ let serverPorts = mapAttrsToList (_: server: server.port) cfg.servers; in { - imports = [ ./erase-your-darlings.nix ]; - - # yes I know there's a NixOS minecraft module but it uses the - # Minecraft in nixpkgs whereas I want to run modded servers and - # packaging one is a pain. - options.nixfiles.minecraft = { - enable = mkOption { type = types.bool; default = false; }; - dataDir = mkOption { type = types.path; default = "/var/lib/minecraft"; }; - servers = mkOption { - type = types.attrsOf (types.submodule - { - options = { - autoStart = mkOption { type = types.bool; default = true; }; - port = mkOption { type = types.int; }; - jar = mkOption { type = types.str; default = "minecraft-server.jar"; }; - jre = mkOption { type = types.package; default = pkgs.jdk17_headless; }; - jvmOpts = mkOption { type = types.separatedString " "; default = "-Xmx4G -Xms4G -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M"; }; - }; - } - ); - default = { }; - }; - }; + imports = [ + ./erase-your-darlings.nix + ./options.nix + ]; config = mkIf cfg.enable { # from https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/games/minecraft-server.nix diff --git a/shared/minecraft/options.nix b/shared/minecraft/options.nix new file mode 100644 index 00000000..c809bc9e --- /dev/null +++ b/shared/minecraft/options.nix @@ -0,0 +1,24 @@ +{ lib, pkgs, ... }: + +with lib; + +{ + options.nixfiles.minecraft = { + enable = mkOption { type = types.bool; default = false; }; + dataDir = mkOption { type = types.path; default = "/var/lib/minecraft"; }; + servers = mkOption { + type = types.attrsOf (types.submodule + { + options = { + autoStart = mkOption { type = types.bool; default = true; }; + port = mkOption { type = types.int; }; + jar = mkOption { type = types.str; default = "minecraft-server.jar"; }; + jre = mkOption { type = types.package; default = pkgs.jdk17_headless; }; + jvmOpts = mkOption { type = types.separatedString " "; default = "-Xmx4G -Xms4G -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M"; }; + }; + } + ); + default = { }; + }; + }; +} diff --git a/shared/oci-containers/default.nix b/shared/oci-containers/default.nix index f4ea9a33..f9d460ef 100644 --- a/shared/oci-containers/default.nix +++ b/shared/oci-containers/default.nix @@ -69,36 +69,6 @@ let volumes = map (mkVolumeDef container) volumes; }; - portOptions = { - host = mkOption { type = types.int; }; - inner = mkOption { type = types.int; }; - }; - - volumeOptions = { - name = mkOption { type = types.nullOr types.str; default = null; }; - host = mkOption { type = types.nullOr types.str; default = null; }; - inner = mkOption { type = types.str; }; - }; - - containerOptions = { - /* regular oci-containers */ - autoStart = mkOption { type = types.bool; default = true; }; - cmd = mkOption { type = types.listOf types.str; default = [ ]; }; - dependsOn = mkOption { type = types.listOf types.str; default = [ ]; }; - environment = mkOption { type = types.attrsOf types.str; default = { }; }; - environmentFiles = mkOption { type = types.listOf types.path; default = [ ]; }; - extraOptions = mkOption { type = types.listOf types.str; default = [ ]; }; - image = mkOption { type = types.str; }; - login.username = mkOption { type = types.nullOr types.str; default = null; }; - login.passwordFile = mkOption { type = types.nullOr types.str; default = null; }; - login.registry = mkOption { type = types.nullOr types.str; default = null; }; - /* changed */ - ports = mkOption { type = types.listOf (types.submodule { options = portOptions; }); default = [ ]; }; - volumes = mkOption { type = types.listOf (types.submodule { options = volumeOptions; }); default = [ ]; }; - /* new options */ - pullOnStart = mkOption { type = types.bool; default = true; }; - }; - cfg = config.nixfiles.oci-containers; allContainers = @@ -116,34 +86,9 @@ let attrsets.unionOfDisjoint cfg.containers podContainers; in { - options.nixfiles.oci-containers = { - backend = mkOption { type = types.enum [ "docker" "podman" ]; default = "docker"; }; - containers = mkOption { - type = types.attrsOf (types.submodule ({ name, ... }: { - options = - containerOptions // - { - pod = mkOption { type = types.nullOr types.str; default = null; }; - network = mkOption { type = types.nullOr types.str; default = null; }; - volumeSubDir = mkOption { type = types.str; default = name; }; - }; - })); - default = { }; - }; - pods = mkOption { - type = types.attrsOf (types.submodule ({ name, ... }: { - options = { - containers = mkOption { - type = types.attrsOf (types.submodule { options = containerOptions; }); - default = { }; - }; - volumeSubDir = mkOption { type = types.str; default = name; }; - }; - })); - default = { }; - }; - volumeBaseDir = mkOption { type = types.str; }; - }; + imports = [ + ./options.nix + ]; config = { virtualisation.${cfg.backend}.autoPrune.enable = true; diff --git a/shared/oci-containers/options.nix b/shared/oci-containers/options.nix new file mode 100644 index 00000000..b411a4ed --- /dev/null +++ b/shared/oci-containers/options.nix @@ -0,0 +1,64 @@ +{ lib, ... }: + +with lib; +let + portOptions = { + host = mkOption { type = types.int; }; + inner = mkOption { type = types.int; }; + }; + + volumeOptions = { + name = mkOption { type = types.nullOr types.str; default = null; }; + host = mkOption { type = types.nullOr types.str; default = null; }; + inner = mkOption { type = types.str; }; + }; + + containerOptions = { + /* regular oci-containers */ + autoStart = mkOption { type = types.bool; default = true; }; + cmd = mkOption { type = types.listOf types.str; default = [ ]; }; + dependsOn = mkOption { type = types.listOf types.str; default = [ ]; }; + environment = mkOption { type = types.attrsOf types.str; default = { }; }; + environmentFiles = mkOption { type = types.listOf types.path; default = [ ]; }; + extraOptions = mkOption { type = types.listOf types.str; default = [ ]; }; + image = mkOption { type = types.str; }; + login.username = mkOption { type = types.nullOr types.str; default = null; }; + login.passwordFile = mkOption { type = types.nullOr types.str; default = null; }; + login.registry = mkOption { type = types.nullOr types.str; default = null; }; + /* changed */ + ports = mkOption { type = types.listOf (types.submodule { options = portOptions; }); default = [ ]; }; + volumes = mkOption { type = types.listOf (types.submodule { options = volumeOptions; }); default = [ ]; }; + /* new options */ + pullOnStart = mkOption { type = types.bool; default = true; }; + }; +in +{ + options.nixfiles.oci-containers = { + backend = mkOption { type = types.enum [ "docker" "podman" ]; default = "docker"; }; + containers = mkOption { + type = types.attrsOf (types.submodule ({ name, ... }: { + options = + containerOptions // + { + pod = mkOption { type = types.nullOr types.str; default = null; }; + network = mkOption { type = types.nullOr types.str; default = null; }; + volumeSubDir = mkOption { type = types.str; default = name; }; + }; + })); + default = { }; + }; + pods = mkOption { + type = types.attrsOf (types.submodule ({ name, ... }: { + options = { + containers = mkOption { + type = types.attrsOf (types.submodule { options = containerOptions; }); + default = { }; + }; + volumeSubDir = mkOption { type = types.str; default = name; }; + }; + })); + default = { }; + }; + volumeBaseDir = mkOption { type = types.str; }; + }; +} diff --git a/shared/options.nix b/shared/options.nix new file mode 100644 index 00000000..3a5fa8ab --- /dev/null +++ b/shared/options.nix @@ -0,0 +1,9 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.firewall = { + ipBlocklistFile = mkOption { type = types.nullOr types.str; default = null; }; + }; +} diff --git a/shared/pleroma/default.nix b/shared/pleroma/default.nix index 1fe9bcb6..e14d7e21 100644 --- a/shared/pleroma/default.nix +++ b/shared/pleroma/default.nix @@ -6,20 +6,10 @@ let backend = config.nixfiles.oci-containers.backend; in { - imports = [ ./erase-your-darlings.nix ]; - - options.nixfiles.pleroma = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 46283; }; - pgTag = mkOption { type = types.str; default = "13"; }; - domain = mkOption { type = types.str; }; - faviconPath = mkOption { type = types.nullOr types.path; default = null; }; - instanceName = mkOption { type = types.str; default = cfg.domain; }; - adminEmail = mkOption { type = types.str; default = "mike@barrucadu.co.uk"; }; - notifyEmail = mkOption { type = types.str; default = cfg.adminEmail; }; - allowRegistration = mkOption { type = types.bool; default = false; }; - secretsFile = mkOption { type = types.str; }; - }; + imports = [ + ./erase-your-darlings.nix + ./options.nix + ]; config = mkIf cfg.enable { services.pleroma.enable = true; @@ -67,9 +57,9 @@ in environment = { DOMAIN = cfg.domain; PORT = toString cfg.port; - INSTANCE_NAME = cfg.instanceName; + INSTANCE_NAME = if cfg.instanceName == null then cfg.domain else cfg.instanceName; ADMIN_EMAIL = cfg.adminEmail; - NOTIFY_EMAIL = cfg.notifyEmail; + NOTIFY_EMAIL = if cfg.notifyEmail == null then cfg.adminEmail else cfg.notifyEmail; ALLOW_REGISTRATION = if cfg.allowRegistration then "true" else "false"; }; serviceConfig.BindPaths = diff --git a/shared/pleroma/options.nix b/shared/pleroma/options.nix new file mode 100644 index 00000000..f54b421a --- /dev/null +++ b/shared/pleroma/options.nix @@ -0,0 +1,18 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.pleroma = { + enable = mkOption { type = types.bool; default = false; }; + port = mkOption { type = types.int; default = 46283; }; + pgTag = mkOption { type = types.str; default = "13"; }; + domain = mkOption { type = types.str; }; + faviconPath = mkOption { type = types.nullOr types.path; default = null; }; + instanceName = mkOption { type = types.nullOr types.str; default = null; }; + adminEmail = mkOption { type = types.str; default = "mike@barrucadu.co.uk"; }; + notifyEmail = mkOption { type = types.nullOr types.str; default = null; }; + allowRegistration = mkOption { type = types.bool; default = false; }; + secretsFile = mkOption { type = types.str; }; + }; +} diff --git a/shared/resolved/default.nix b/shared/resolved/default.nix index c564c4af..41858486 100644 --- a/shared/resolved/default.nix +++ b/shared/resolved/default.nix @@ -5,20 +5,9 @@ let cfg = config.nixfiles.resolved; in { - options.nixfiles.resolved = { - enable = mkOption { type = types.bool; default = false; }; - address = mkOption { type = types.str; default = "0.0.0.0:53"; }; - metrics_address = mkOption { type = types.str; default = "127.0.0.1:9420"; }; - authoritative_only = mkOption { type = types.bool; default = false; }; - protocol_mode = mkOption { type = types.str; default = "only-v4"; }; - forward_address = mkOption { type = types.nullOr types.str; default = null; }; - cache_size = mkOption { type = types.int; default = 512; }; - hosts_dirs = mkOption { type = types.listOf types.str; default = [ ]; }; - zones_dirs = mkOption { type = types.listOf types.str; default = [ ]; }; - use_default_zones = mkOption { type = types.bool; default = true; }; - log_level = mkOption { type = types.str; default = "dns_resolver=info,resolved=info"; }; - log_format = mkOption { type = types.str; default = "json,no-time"; }; - }; + imports = [ + ./options.nix + ]; config = mkIf cfg.enable { systemd.services.resolved = { diff --git a/shared/resolved/options.nix b/shared/resolved/options.nix new file mode 100644 index 00000000..ad7bda04 --- /dev/null +++ b/shared/resolved/options.nix @@ -0,0 +1,20 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.resolved = { + enable = mkOption { type = types.bool; default = false; }; + address = mkOption { type = types.str; default = "0.0.0.0:53"; }; + metrics_address = mkOption { type = types.str; default = "127.0.0.1:9420"; }; + authoritative_only = mkOption { type = types.bool; default = false; }; + protocol_mode = mkOption { type = types.str; default = "only-v4"; }; + forward_address = mkOption { type = types.nullOr types.str; default = null; }; + cache_size = mkOption { type = types.int; default = 512; }; + hosts_dirs = mkOption { type = types.listOf types.str; default = [ ]; }; + zones_dirs = mkOption { type = types.listOf types.str; default = [ ]; }; + use_default_zones = mkOption { type = types.bool; default = true; }; + log_level = mkOption { type = types.str; default = "dns_resolver=info,resolved=info"; }; + log_format = mkOption { type = types.str; default = "json,no-time"; }; + }; +} diff --git a/shared/rtorrent/default.nix b/shared/rtorrent/default.nix index df3608ab..a59a7443 100644 --- a/shared/rtorrent/default.nix +++ b/shared/rtorrent/default.nix @@ -46,24 +46,10 @@ let in { - imports = [ ./erase-your-darlings.nix ]; - - options.nixfiles.rtorrent = { - enable = mkOption { type = types.bool; default = false; }; - downloadDir = mkOption { type = types.str; }; - watchDir = mkOption { type = types.str; }; - user = mkOption { type = types.str; }; - logLevels = mkOption { type = types.listOf types.str; default = [ "info" ]; }; - openFirewall = mkOption { type = types.bool; default = true; }; - portRange = { - from = mkOption { type = types.int; default = 50000; }; - to = mkOption { type = types.int; default = 50000; }; - }; - flood = { - enable = mkOption { type = types.bool; default = true; }; - port = mkOption { type = types.int; default = 45904; }; - }; - }; + imports = [ + ./erase-your-darlings.nix + ./options.nix + ]; config = mkIf cfg.enable { networking.firewall.allowedTCPPortRanges = mkIf cfg.openFirewall [ cfg.portRange ]; diff --git a/shared/rtorrent/options.nix b/shared/rtorrent/options.nix new file mode 100644 index 00000000..f17c4725 --- /dev/null +++ b/shared/rtorrent/options.nix @@ -0,0 +1,22 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.rtorrent = { + enable = mkOption { type = types.bool; default = false; }; + downloadDir = mkOption { type = types.str; }; + watchDir = mkOption { type = types.str; }; + user = mkOption { type = types.str; }; + logLevels = mkOption { type = types.listOf types.str; default = [ "info" ]; }; + openFirewall = mkOption { type = types.bool; default = true; }; + portRange = { + from = mkOption { type = types.int; default = 50000; }; + to = mkOption { type = types.int; default = 50000; }; + }; + flood = { + enable = mkOption { type = types.bool; default = true; }; + port = mkOption { type = types.int; default = 45904; }; + }; + }; +} diff --git a/shared/umami/default.nix b/shared/umami/default.nix index 4cf8fda1..12ad162b 100644 --- a/shared/umami/default.nix +++ b/shared/umami/default.nix @@ -6,13 +6,9 @@ let backend = config.nixfiles.oci-containers.backend; in { - options.nixfiles.umami = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 46489; }; - postgresTag = mkOption { type = types.str; default = "13"; }; - umamiTag = mkOption { type = types.str; default = "postgresql-latest"; }; - environmentFile = mkOption { type = types.str; }; - }; + imports = [ + ./options.nix + ]; config = mkIf cfg.enable { nixfiles.oci-containers.pods.umami = { diff --git a/shared/umami/options.nix b/shared/umami/options.nix new file mode 100644 index 00000000..23259cf1 --- /dev/null +++ b/shared/umami/options.nix @@ -0,0 +1,13 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.umami = { + enable = mkOption { type = types.bool; default = false; }; + port = mkOption { type = types.int; default = 46489; }; + postgresTag = mkOption { type = types.str; default = "13"; }; + umamiTag = mkOption { type = types.str; default = "postgresql-latest"; }; + environmentFile = mkOption { type = types.str; }; + }; +} From e63b153cd9d4ff6b40f32eb1d311f2a3a3e4d4f1 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 15:07:58 +0100 Subject: [PATCH 02/29] Generate a basic reference documentation site --- .github/workflows/ci.yaml | 16 ++++++++ .gitignore | 1 + docs/.gitignore | 7 ++++ docs/book.toml | 17 ++++++++ docs/src/SUMMARY.md | 8 ++++ flake.nix | 16 +++----- scripts/documentation.sh | 86 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 .gitignore create mode 100644 docs/.gitignore create mode 100644 docs/book.toml create mode 100644 docs/src/SUMMARY.md create mode 100644 scripts/documentation.sh diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bbf61959..8d3a2bf5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,3 +17,19 @@ jobs: nix run .#fmt nix run .#lint git diff --exit-code + - name: Check mdbook-admonish changes are not committed + run: | + if grep -q "do not edit: managed by \`mdbook-admonish install\`" docs/book.toml; then + echo "remove generated mdbook-admonish lines from docs/books.toml" >&2 + exit 1 + fi + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v23 + with: + nix_path: nixpkgs=channel:nixos-unstable + - name: Check documentation site builds + run: nix run .#documentation diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..0baf0152 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/_site diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..5b2a6158 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,7 @@ +book + +# generated by the build script +src/README.md +src/modules.md +src/options.md +mdbook-admonish.css diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 00000000..61c7d18f --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,17 @@ +[book] +title = "nixfiles" +authors = ["Michael Walker (barrucadu)"] +description = "My NixOS configuration and assorted other crap, powered by flakes." +language = "en" +multilingual = false + +[build] +create-missing = false + +[output.html] +git-repository-url = "https://github.com/barrucadu/nixfiles" +cname = "nixfiles.docs.barrucadu.co.uk" + +[preprocessor.admonish] +on_failure = "bail" +command = "mdbook-admonish" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 00000000..bd2aa934 --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,8 @@ +# Summary + +- [README](./README.md) + +# Reference + +- [Modules](./modules.md) +- [Options](./options.md) diff --git a/flake.nix b/flake.nix index b42d0ea5..a719182d 100644 --- a/flake.nix +++ b/flake.nix @@ -89,7 +89,7 @@ ${pkgs.lib.fileContents ./scripts/secrets.sh} ''; - option-docs = + documentation = let eval = pkgs.lib.evalModules { modules = [ @@ -115,15 +115,11 @@ warningsAreErrors = false; }; in - mkApp "options-json" '' - case "$1" in - "json") - cat ${optionsDoc.optionsJSON}/share/doc/nixos/options.json - ;; - *) - cat ${optionsDoc.optionsCommonMark} - ;; - esac + mkApp "documentation" '' + PATH=${with pkgs; lib.makeBinPath [ coreutils mdbook mdbook-admonish python3 ]} + export NIXOS_OPTIONS_JSON="${optionsDoc.optionsJSON}/share/doc/nixos/options.json" + + ${pkgs.lib.fileContents ./scripts/documentation.sh} ''; }; }; diff --git a/scripts/documentation.sh b/scripts/documentation.sh new file mode 100644 index 00000000..6863c337 --- /dev/null +++ b/scripts/documentation.sh @@ -0,0 +1,86 @@ +set -e + +pushd docs +mdbook-admonish install +popd + +cp README.markdown docs/src/README.md + +python3 - <<'EOF' > docs/src/modules.md +import json +import os + +print("# Modules") +print("") + +with open(os.getenv("NIXOS_OPTIONS_JSON"), "r") as f: + options = json.load(f) + +modules = {} +for key, defn in options.items(): + module_name = defn["declarations"][0].split("/shared/")[1].replace("/options.nix", "") + if module_name == "options.nix": + # this is the top-level `shared` file + module_name = "" + modules.setdefault(module_name, []).append(key) + +for module in sorted(modules.keys()): + module_name = "<shared>" if module == "" else module + source_file = f"shared/{module}/default.nix".replace("//", "/") + + print(f"## {module_name}") + + has_doc = False + with open(source_file, "r") as f: + for line in f: + if line.startswith("#"): + has_doc = True + print(line[1:].strip()) + else: + break + if not has_doc: + print("This module has no description.") + + print("\n**Options:**\n") + for option in modules[module]: + anchor = "".join(c for c in option if c.isalpha() or c in "-_").lower() + print(f"- [`{option}`](./options.md#{anchor})") + print(f"\n**Declared in:** [{source_file}](https://github.com/barrucadu/nixfiles/blob/master/{source_file})") + print("") +EOF + +python3 - <<'EOF' > docs/src/options.md +import json +import os + +print("# Options") +print("") + +with open(os.getenv("NIXOS_OPTIONS_JSON"), "r") as f: + options = json.load(f) + +for option in sorted(options.keys()): + defn = options[option] + option_name = option.replace("*", "\\*").replace("<", "<").replace(">", ">") + source_file = "shared/" + defn["declarations"][0].split("/shared/")[1] + + print(f"## {option_name}") + if isinstance(defn["description"], str): + print(f"\n{defn['description']}") + else: + print(f"\n{defn['description']['text']}") + print(f"\n**Type:** `{defn['type']}`") + if "default" in defn: + print(f"\n**Default:** `{defn['default']['text']}`") + if "example" in defn: + print(f"\n**Example:** `{defn['example']['text']}`") + print(f"\n**Declared in:** [{source_file}](https://github.com/barrucadu/nixfiles/blob/master/{source_file})") + print("") +EOF + +mdbook build docs +mv docs/book _site + +chmod -c -R +rX _site | while read -r line; do + echo "::warning title=Invalid file permissions automatically fixed::$line" +done From 0dfb3b04c7233b2e68b00a912a5505f6c5cdc00d Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 15:51:05 +0100 Subject: [PATCH 03/29] Add action to deploy the documentation site --- .github/workflows/deploy-documentation.yml | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/deploy-documentation.yml diff --git a/.github/workflows/deploy-documentation.yml b/.github/workflows/deploy-documentation.yml new file mode 100644 index 00000000..58332bfe --- /dev/null +++ b/.github/workflows/deploy-documentation.yml @@ -0,0 +1,51 @@ +name: Deploy documentation site + +on: + # Runs on pushes targeting the default branch + push: + branches: ["master"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v3 + - name: Install nix + uses: cachix/install-nix-action@v23 + with: + nix_path: nixpkgs=channel:nixos-unstable + - name: Build + run: nix run .#documentation + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 From 937f720d6758be0e85032ec7b95c181f64ac0bb3 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 15:43:00 +0100 Subject: [PATCH 04/29] Document `backups` module and options --- shared/backups/default.nix | 24 +++++++++ shared/backups/options.nix | 105 +++++++++++++++++++++++++++++++++---- 2 files changed, 119 insertions(+), 10 deletions(-) diff --git a/shared/backups/default.nix b/shared/backups/default.nix index 1539bf9f..1143051a 100644 --- a/shared/backups/default.nix +++ b/shared/backups/default.nix @@ -1,3 +1,27 @@ +# Manage regular incremental and full backups with [Duplicity][]. +# +# Backups are encrypted and uploaded to the `barrucadu-backups` s3 bucket, +# [defined in the ops repo][]. +# +# Check the status of a backup collection with: +# +# ```bash +# nix run .#backups # for the current host +# nix run .#backups status # for the current host +# nix run .#backups status # for another host +# ``` +# +# Restore a backup to `/tmp/backup-restore` with: +# +# ```bash +# nix run .#backups restore # for the current host +# nix run .#backups restore # for another host +# ``` +# +# Change the restore target by setting `$RESTORE_DIR`. +# +# [Duplicity]: https://duplicity.gitlab.io/ +# [defined in the ops repo]: https://github.com/barrucadu/ops/blob/master/aws/backups.tf { config, lib, pkgs, ... }: with lib; diff --git a/shared/backups/options.nix b/shared/backups/options.nix index b636721c..8549f275 100644 --- a/shared/backups/options.nix +++ b/shared/backups/options.nix @@ -4,22 +4,107 @@ with lib; { options.nixfiles.backups = { - enable = mkOption { type = types.bool; default = false; }; - scripts = mkOption { type = types.attrsOf types.str; default = { }; }; - pythonScripts = mkOption { type = types.attrsOf types.str; default = { }; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the backup service. + ''; + }; + + scripts = mkOption { + type = types.attrsOf types.str; + default = { }; + description = mdDoc '' + Attrset of bash scripts to run. The name is the name of the script's + working directory. + ''; + }; + + pythonScripts = mkOption { + type = types.attrsOf types.str; + default = { }; + description = mdDoc '' + Attrset of python scripts to run. The name is the name of the script's + working directory. + ''; + }; + sudoRules = mkOption { type = types.listOf (types.submodule { options = { - command = mkOption { type = types.str; }; - runAs = mkOption { type = types.str; default = "ALL:ALL"; }; + command = mkOption { + type = types.str; + description = mdDoc '' + The command for which the rule applies. + ''; + }; + runAs = mkOption { + type = types.str; + default = "ALL:ALL"; + description = mdDoc '' + The user / group under which the command is allowed to run. + + A user can be specified using just the username: `"foo"`. It is + also possible to specify a user/group combination using + `"foo:bar"` or to only allow running as a specific group with + `":bar"`. + ''; + }; }; }); default = { }; + description = mdDoc '' + List of additional sudo rules to grant the backup user. + ''; + }; + + environmentFile = mkOption { + type = types.str; + description = mdDoc '' + Environment file to be passed to the systemd services. This needs to contain: + + - `PASSPHRASE` - the password duplicity uses to encrypt the files + - `AWS_ACCESS_KEY` / `AWS_SECRET_ACCESS_KEY` / `AWS_DEFAULT_REGION` - + the AWS credentials used to upload the backup to s3 and publish to the + SNS topic + - `TOPIC_ARN` - the SNS topic to publish to if an error occurs + + If any of the `scripts` or `pythonScripts` need secrets, those should be + specified here. + ''; + }; + + onCalendarFull = mkOption { + type = types.str; + default = "monthly"; + description = mdDoc '' + The cadence of the full backup job. + ''; + }; + + onCalendarIncr = mkOption { + type = types.str; + default = "Mon, 04:00"; + description = mdDoc '' + The cadence of the incremental backup job. + ''; + }; + + user = mkOption { + type = types.str; + default = "barrucadu"; + description = mdDoc '' + The user to generate the backup as. + ''; + }; + + group = mkOption { + type = types.str; + default = "users"; + description = mdDoc '' + The group to generate the backup as. + ''; }; - environmentFile = mkOption { type = types.str; }; - onCalendarFull = mkOption { type = types.str; default = "monthly"; }; - onCalendarIncr = mkOption { type = types.str; default = "Mon, 04:00"; }; - user = mkOption { type = types.str; default = "barrucadu"; }; - group = mkOption { type = types.str; default = "users"; }; }; } From 619cd598ecc2d54e37ed9b0a4ddec9e0c20081e2 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 16:10:09 +0100 Subject: [PATCH 05/29] Document `bookdb` module and options --- shared/bookdb/default.nix | 14 +++++++++ shared/bookdb/options.nix | 66 ++++++++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/shared/bookdb/default.nix b/shared/bookdb/default.nix index ad5baa8c..b6751c35 100644 --- a/shared/bookdb/default.nix +++ b/shared/bookdb/default.nix @@ -1,3 +1,17 @@ +# [bookdb][] is a webapp to keep track of all my books, with a public instance +# on [bookdb.barrucadu.co.uk][]. +# +# bookdb uses a containerised elasticsearch database, it also stores uploaded +# book cover images. +# +# If the `backups` module is enabled, adds a script to backup the database and +# uploaded files. +# +# If the `erase-your-darlings` module is enabled, stores its data on the +# persistent volume. +# +# [bookdb]: https://github.com/barrucadu/bookdb +# [bookdb.barrucadu.co.uk]: https://bookdb.barrucadu.co.uk/ { config, lib, pkgs, ... }: with lib; diff --git a/shared/bookdb/options.nix b/shared/bookdb/options.nix index f93565f2..615e41d1 100644 --- a/shared/bookdb/options.nix +++ b/shared/bookdb/options.nix @@ -4,12 +4,64 @@ with lib; { options.nixfiles.bookdb = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 46667; }; - esPort = mkOption { type = types.int; default = 47164; }; - esTag = mkOption { type = types.str; default = "8.0.0"; }; - baseURI = mkOption { type = types.str; }; - readOnly = mkOption { type = types.bool; default = false; }; - dataDir = mkOption { type = types.str; default = "/srv/bookdb"; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the bookdb service. + ''; + }; + + port = mkOption { + type = types.int; + default = 46667; + description = mdDoc '' + Port (on 127.0.0.1) to expose the bookdb service on. + ''; + }; + + esPort = mkOption { + type = types.int; + default = 47164; + description = mdDoc '' + Port (on 127.0.0.1) to expose the elasticsearch container on. + ''; + }; + + esTag = mkOption { + type = types.str; + default = "8.0.0"; + description = mdDoc '' + Tag to use of the `elasticsearch` container image. + ''; + }; + + baseURI = mkOption { + type = types.str; + example = "https://bookdb.barrucadu.co.uk"; + description = mdDoc '' + URI which the service will be exposed on, used to generate URLs. + ''; + }; + + readOnly = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Whether to launch the service in "read-only" mode. Enable this if + exposing it to a public network. + ''; + }; + + dataDir = mkOption { + type = types.str; + default = "/srv/bookdb"; + description = mdDoc '' + Directory to store uploaded files to. + + If the `erase-your-darlings` module is enabled, this is overridden to be + on the persistent volume. + ''; + }; }; } From 8395057ade52025a4e488141d066853d075a2088 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 16:15:54 +0100 Subject: [PATCH 06/29] Document `bookmarks` module and options --- shared/bookmarks/default.nix | 12 +++++++ shared/bookmarks/options.nix | 64 ++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/shared/bookmarks/default.nix b/shared/bookmarks/default.nix index ffad848b..a19e55d8 100644 --- a/shared/bookmarks/default.nix +++ b/shared/bookmarks/default.nix @@ -1,3 +1,15 @@ +# [bookmarks][] is a webapp to keep track of all my bookmarks, with a public +# instance on [bookmarks.barrucadu.co.uk][]. +# +# bookmarks uses a containerised elasticsearch database. +# +# If the `backups` module is enabled, adds a script to backup the database. +# +# If the `erase-your-darlings` module is enabled, stores its data on the +# persistent volume. +# +# [bookmarks]: https://github.com/barrucadu/bookmarks +# [bookmarks.barrucadu.co.uk]: https://bookmarks.barrucadu.co.uk/ { config, lib, pkgs, ... }: with lib; diff --git a/shared/bookmarks/options.nix b/shared/bookmarks/options.nix index 670bb2d5..66fdb6bc 100644 --- a/shared/bookmarks/options.nix +++ b/shared/bookmarks/options.nix @@ -4,12 +4,62 @@ with lib; { options.nixfiles.bookmarks = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 48372; }; - esPort = mkOption { type = types.int; default = 43389; }; - esTag = mkOption { type = types.str; default = "8.0.0"; }; - baseURI = mkOption { type = types.str; }; - readOnly = mkOption { type = types.bool; default = false; }; - environmentFile = mkOption { type = types.nullOr types.str; default = null; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the bookmarks service. + ''; + }; + + port = mkOption { + type = types.int; + default = 48372; + description = mdDoc '' + Port (on 127.0.0.1) to expose the bookmarks service on. + ''; + }; + + esPort = mkOption { + type = types.int; + default = 43389; + description = mdDoc '' + Port (on 127.0.0.1) to expose the elasticsearch container on. + ''; + }; + + esTag = mkOption { + type = types.str; + default = "8.0.0"; + description = mdDoc '' + Tag to use of the `elasticsearch` container image. + ''; + }; + + baseURI = mkOption { + type = types.str; + example = "https://bookmarks.barrucadu.co.uk"; + description = mdDoc '' + URI which the service will be exposed on, used to generate URLs. + ''; + }; + + readOnly = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Whether to launch the service in "read-only" mode. Enable this if + exposing it to a public network. + ''; + }; + + environmentFile = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Environment file to be passed to the systemd services. This needs to + contain a `YOUTUBE_API_KEY` if not running in read-only mode. + ''; + }; }; } From 39f53fcc46412fb4d4ed06ff0928a33eda2faa8c Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 16:31:54 +0100 Subject: [PATCH 07/29] Document `concourse` module and options --- shared/concourse/default.nix | 14 +++++++ shared/concourse/options.nix | 78 ++++++++++++++++++++++++++++++++---- 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/shared/concourse/default.nix b/shared/concourse/default.nix index 7d8e8bab..56db2b56 100644 --- a/shared/concourse/default.nix +++ b/shared/concourse/default.nix @@ -1,3 +1,17 @@ +# [Concourse CI][] is a "continuous thing-doer", it's a CI / CD tool. This +# module sets up a single-user instance, with GitHub authentication. +# +# Concourse uses a containerised postgres database. +# +# If the `backups` module is enabled, adds a script to backup the database. +# +# If the `erase-your-darlings` module is enabled, stores its data on the +# persistent volume. +# +# Enabling this module also provisions a [Grafana][] dashboard. +# +# [Concourse CI]: https://concourse-ci.org/ +# [Grafana]: https://grafana.com/ { config, lib, pkgs, ... }: with lib; diff --git a/shared/concourse/options.nix b/shared/concourse/options.nix index 340d5172..531da34d 100644 --- a/shared/concourse/options.nix +++ b/shared/concourse/options.nix @@ -4,13 +4,75 @@ with lib; { options.nixfiles.concourse = { - enable = mkOption { type = types.bool; default = false; }; - concourseTag = mkOption { type = types.str; default = "7.8.2"; }; - githubUser = mkOption { type = types.str; default = "barrucadu"; }; - port = mkOption { type = types.int; default = 46498; }; - metricsPort = mkOption { type = types.int; default = 45811; }; - postgresTag = mkOption { type = types.str; default = "13"; }; - workerScratchDir = mkOption { type = types.nullOr types.path; default = null; }; - environmentFile = mkOption { type = types.str; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the Concourse CI service. + ''; + }; + + concourseTag = mkOption { + type = types.str; + default = "7.8.2"; + description = mdDoc '' + Tag to use of the `concourse/concourse` container image. + ''; + }; + + githubUser = mkOption { + type = types.str; + default = "barrucadu"; + description = mdDoc '' + The GitHub user to authenticate with. + ''; + }; + + port = mkOption { + type = types.int; + default = 46498; + description = mdDoc '' + Port (on 127.0.0.1) to expose the Concourse CI web UI on. + ''; + }; + + metricsPort = mkOption { + type = types.int; + default = 45811; + description = mdDoc '' + Port (on 127.0.0.1) to expose the Concourse CI Prometheus metrics on. + ''; + }; + + postgresTag = mkOption { + type = types.str; + default = "13"; + description = mdDoc '' + Tag to use of the `postgres` container image. + ''; + }; + + workerScratchDir = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + Mount a directory from the host into the worker container to use as + temporary storage. This is useful if the filesystem used for container + volumes isn't very big. + ''; + }; + + environmentFile = mkOption { + type = types.str; + description = mdDoc '' + Environment file to be passed into the containers. This needs to contain: + + - `CONCOURSE_GITHUB_CLIENT_ID` / `CONCOURSE_GITHUB_CLIENT_SECRET` - the + GitHub OAuth credentials used for user authentication + - `CONCOURSE_AWS_SSM_REGION` / `CONCOURSE_AWS_SSM_ACCESS_KEY` / + `CONCOURSE_AWS_SSM_SECRET_KEY` - the AWS credentials used to fetch + secrets from SSM + ''; + }; }; } From 75f20910713483bc6749f51d8646bb03cb8ad1a2 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 16:47:39 +0100 Subject: [PATCH 08/29] Document `erase-your-darlings` module and options --- shared/erase-your-darlings/default.nix | 10 +++++ shared/erase-your-darlings/options.nix | 55 +++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/shared/erase-your-darlings/default.nix b/shared/erase-your-darlings/default.nix index b77d2ac8..9bf4752c 100644 --- a/shared/erase-your-darlings/default.nix +++ b/shared/erase-your-darlings/default.nix @@ -1,3 +1,13 @@ +# Wipe `/` on boot, inspired by ["erase your darlings"][]. +# +# This module is responsible for configuring standard NixOS options and +# services, all of my modules have their own `erase-your-darlings.nix` file +# which makes any changes that they need. +# +# This requires a setting up ZFS in a specific way when first installing NixOS. +# See the [README](./index.html#optional-configure-wiping--on-boot). +# +# ["erase your darlings"]: https://grahamc.com/blog/erase-your-darlings/ { config, lib, ... }: with lib; diff --git a/shared/erase-your-darlings/options.nix b/shared/erase-your-darlings/options.nix index b4fdeee5..79184194 100644 --- a/shared/erase-your-darlings/options.nix +++ b/shared/erase-your-darlings/options.nix @@ -4,10 +4,55 @@ with lib; { options.nixfiles.eraseYourDarlings = { - enable = mkOption { type = types.bool; default = false; }; - barrucaduPasswordFile = mkOption { type = types.str; }; - rootSnapshot = mkOption { type = types.str; default = "local/volatile/root@blank"; }; - persistDir = mkOption { type = types.path; default = "/persist"; }; - machineId = mkOption { type = types.str; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable wiping `/` on boot and storing persistent data in + `''${persistDir}`. + ''; + }; + + barrucaduPasswordFile = mkOption { + type = types.str; + description = mdDoc '' + Path to a file containing the hashed password for `barrucadu`. This + file must be available in early boot. + + If using [sops-nix](https://github.com/Mic92/sops-nix) set the + `neededForUsers` option on the secret. + ''; + }; + + rootSnapshot = mkOption { + type = types.str; + default = "local/volatile/root@blank"; + description = mdDoc '' + ZFS snapshot to roll back to on boot. + ''; + }; + + persistDir = mkOption { + type = types.path; + default = "/persist"; + description = mdDoc '' + Persistent directory which will not be erased. This must be on a + different ZFS dataset that will not be wiped when rolling back to the + `rootSnapshot`. + + This module moves various files from `/` to here. + ''; + }; + + machineId = mkOption { + type = types.str; + example = "64b1b10f3bef4616a7faf5edf1ef3ca5"; + description = mdDoc '' + An arbitrary 32-character hexadecimal string, used to identify the host. + This is needed for journalctl logs from previous boots to be accessible. + + See [the systemd documentation](https://www.freedesktop.org/software/systemd/man/machine-id.html). + ''; + }; }; } From 13c65aeaaffa4a61fb9b8f043f3623b1ea53f070 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 21:37:12 +0100 Subject: [PATCH 09/29] Document `finder` module and options --- shared/finder/default.nix | 8 ++++++++ shared/finder/options.nix | 43 ++++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/shared/finder/default.nix b/shared/finder/default.nix index ba85389d..a7b7a2e8 100644 --- a/shared/finder/default.nix +++ b/shared/finder/default.nix @@ -1,3 +1,11 @@ +# finder is a webapp to read downloaded manga. There is no public deployment. +# +# finder uses a containerised elasticsearch database, and requires read access +# to the filesystem where manga is stored. It does not manage the manga, only +# provides an interface to search and read. +# +# The database can be recreated from the manga files, so this module does not +# include a backup script. { config, lib, ... }: with lib; diff --git a/shared/finder/options.nix b/shared/finder/options.nix index 8dc07a2e..6be42403 100644 --- a/shared/finder/options.nix +++ b/shared/finder/options.nix @@ -4,10 +4,43 @@ with lib; { options.nixfiles.finder = { - enable = mkOption { type = types.bool; default = false; }; - image = mkOption { type = types.str; }; - port = mkOption { type = types.int; default = 44986; }; - esTag = mkOption { type = types.str; default = "8.0.0"; }; - mangaDir = mkOption { type = types.path; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the finder service. + ''; + }; + + image = mkOption { + type = types.str; + description = mdDoc '' + Container image to use. + ''; + }; + + port = mkOption { + type = types.int; + default = 44986; + description = mdDoc '' + Port (on 127.0.0.1) to expose the finder service on. + ''; + }; + + esTag = mkOption { + type = types.str; + default = "8.0.0"; + description = mdDoc '' + Tag to use of the `elasticsearch` container image. + ''; + }; + + mangaDir = mkOption { + type = types.path; + example = "/mnt/nas/manga"; + description = mdDoc '' + Directory to serve manga files from. + ''; + }; }; } From fff7162358581d7cb23380e514be6fcbc918c424 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 21:44:12 +0100 Subject: [PATCH 10/29] Document `foundryvtt` module and options --- shared/foundryvtt/default.nix | 18 +++++++++++++++--- shared/foundryvtt/options.nix | 31 ++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/shared/foundryvtt/default.nix b/shared/foundryvtt/default.nix index 32a58b2a..449da38f 100644 --- a/shared/foundryvtt/default.nix +++ b/shared/foundryvtt/default.nix @@ -1,6 +1,18 @@ -# FoundryVTT is licensed software and needs to be downloaded after -# purchase. - +# [FoundryVTT][] is a virtual tabletop to run roleplaying games. It is licensed +# software and needs to be downloaded after purchase. This module doesn't +# manage the FoundryVTT program files, only operating it. +# +# The downloaded FoundryVTT program files must be in +# `{nixfiles.foundryvtt.dataDir}/bin`. +# +# If the `backups` module is enabled, adds a script to backup the data files. +# This requires briefly stopping the service, so don't schedule backups during +# game time. +# +# If the `erase-your-darlings` module is enabled, stores its data on the +# persistent volume. +# +# [FoundryVTT]: https://foundryvtt.com/ { config, lib, pkgs, ... }: with lib; diff --git a/shared/foundryvtt/options.nix b/shared/foundryvtt/options.nix index 18901369..45144527 100644 --- a/shared/foundryvtt/options.nix +++ b/shared/foundryvtt/options.nix @@ -4,8 +4,33 @@ with lib; { options.nixfiles.foundryvtt = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 46885; }; - dataDir = mkOption { type = types.str; default = "/var/lib/foundryvtt"; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the FoundryVTT service. + ''; + }; + + port = mkOption { + type = types.int; + default = 46885; + description = mdDoc '' + Port (on 127.0.0.1) to expose FoundryVTT on. + ''; + }; + + dataDir = mkOption { + type = types.str; + default = "/var/lib/foundryvtt"; + description = mdDoc '' + Directory to store data files in. + + The downloaded FoundryVTT program files must be in `''${dataDir}/bin`. + + If the `erase-your-darlings` module is enabled, this is overridden to be + on the persistent volume. + ''; + }; }; } From cf99dd28f32d4eedf1b2e92a2d3e79f25f39fa06 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 21:56:29 +0100 Subject: [PATCH 11/29] Document `minecraft` module and options --- shared/minecraft/default.nix | 19 ++++++++-- shared/minecraft/options.nix | 71 ++++++++++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 10 deletions(-) diff --git a/shared/minecraft/default.nix b/shared/minecraft/default.nix index 544239bb..a89e921d 100644 --- a/shared/minecraft/default.nix +++ b/shared/minecraft/default.nix @@ -1,6 +1,19 @@ -# Yes I know there's a NixOS minecraft module but it uses the Minecraft in -# nixpkgs whereas I want to run modded servers and packaging one is a pain. - +# [Minecraft][] Java Edition runner. Supports multiple servers, with mods. +# This module doesn't manage the Minecraft server files, only operating them. +# +# Yes, I know there's a NixOS minecraft module, but it uses the Minecraft in +# nixpkgs and only runs one server, whereas I want to run multiple modded +# servers. +# +# The Minecraft server files must be in `{nixfiles.minecraft.dataDir}/{name}`. +# +# This module does not include a backup script. Servers must be backed up +# independently. +# +# If the `erase-your-darlings` module is enabled, stores its data on the +# persistent volume. +# +# [Minecraft]: https://www.minecraft.net/en-us { config, lib, pkgs, ... }: with lib; diff --git a/shared/minecraft/options.nix b/shared/minecraft/options.nix index c809bc9e..7f8a4f03 100644 --- a/shared/minecraft/options.nix +++ b/shared/minecraft/options.nix @@ -4,21 +4,78 @@ with lib; { options.nixfiles.minecraft = { - enable = mkOption { type = types.bool; default = false; }; - dataDir = mkOption { type = types.path; default = "/var/lib/minecraft"; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the Minecraft service. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/minecraft"; + description = mdDoc '' + Directory to store data files in. + + If the `erase-your-darlings` module is enabled, this is overridden to be + on the persistent volume. + ''; + }; + servers = mkOption { type = types.attrsOf (types.submodule { options = { - autoStart = mkOption { type = types.bool; default = true; }; - port = mkOption { type = types.int; }; - jar = mkOption { type = types.str; default = "minecraft-server.jar"; }; - jre = mkOption { type = types.package; default = pkgs.jdk17_headless; }; - jvmOpts = mkOption { type = types.separatedString " "; default = "-Xmx4G -Xms4G -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M"; }; + autoStart = mkOption { + type = types.bool; + default = true; + description = mdDoc '' + Start this server on boot. + ''; + }; + + port = mkOption { + type = types.int; + description = mdDoc '' + Port to open in the firewall. This must match the port in the + `server.properties` file. + ''; + }; + + jar = mkOption { + type = types.str; + default = "minecraft-server.jar"; + description = mdDoc '' + Name of the JAR file to use. This file must be in the working + directory. + ''; + }; + + jre = mkOption { + type = types.package; + default = pkgs.jdk17_headless; + description = mdDoc '' + Java runtime package to use. + ''; + }; + + jvmOpts = mkOption { + type = types.separatedString " "; + default = "-Xmx4G -Xms4G -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M"; + description = mdDoc '' + Java runtime arguments. Cargo cult these from a forum post and + then never think about them again. + ''; + }; }; } ); default = { }; + description = mdDoc '' + Attrset of minecraft server definitions. Each server `{name}` is run in + the working directory `''${dataDir}/{name}`. + ''; }; }; } From 3df848b21d23b771869aca1eed7cecbb8074996c Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 23:10:48 +0100 Subject: [PATCH 12/29] Document `pleroma` module and options --- shared/pleroma/default.nix | 11 +++++ shared/pleroma/options.nix | 91 +++++++++++++++++++++++++++++++++----- 2 files changed, 92 insertions(+), 10 deletions(-) diff --git a/shared/pleroma/default.nix b/shared/pleroma/default.nix index e14d7e21..2614b220 100644 --- a/shared/pleroma/default.nix +++ b/shared/pleroma/default.nix @@ -1,3 +1,14 @@ +# [Pleroma][] is a fediverese server. +# +# Pleroma uses a containerised postgres database. +# +# If the `backups` module is enabled, adds a script to backup the database and +# uploaded files. +# +# If the `erase-your-darlings` module is enabled, stores its data on the +# persistent volume. +# +# [Pleroma]: https://pleroma.social/ { config, lib, pkgs, ... }: with lib; diff --git a/shared/pleroma/options.nix b/shared/pleroma/options.nix index f54b421a..3f365480 100644 --- a/shared/pleroma/options.nix +++ b/shared/pleroma/options.nix @@ -4,15 +4,86 @@ with lib; { options.nixfiles.pleroma = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 46283; }; - pgTag = mkOption { type = types.str; default = "13"; }; - domain = mkOption { type = types.str; }; - faviconPath = mkOption { type = types.nullOr types.path; default = null; }; - instanceName = mkOption { type = types.nullOr types.str; default = null; }; - adminEmail = mkOption { type = types.str; default = "mike@barrucadu.co.uk"; }; - notifyEmail = mkOption { type = types.nullOr types.str; default = null; }; - allowRegistration = mkOption { type = types.bool; default = false; }; - secretsFile = mkOption { type = types.str; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the Pleroma service. + ''; + }; + + port = mkOption { + type = types.int; + default = 46283; + description = mdDoc '' + Port (on 127.0.0.1) to expose Pleroma on. + ''; + }; + + pgTag = mkOption { + type = types.str; + default = "13"; + description = mdDoc '' + Tag to use of the `postgres` container image. + ''; + }; + + domain = mkOption { + type = types.str; + example = "social.lainon.life"; + description = mdDoc '' + Domain which Pleroma will be exposed on. + ''; + }; + + faviconPath = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + Path to the favicon file. + ''; + }; + + instanceName = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Name of the instance, defaults to the `''${domain}` if not set. + ''; + }; + + adminEmail = mkOption { + type = types.str; + default = "mike@barrucadu.co.uk"; + description = mdDoc '' + Email address used to contact the server operator. + ''; + }; + + notifyEmail = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Email address used for notification, defaults to the `''${adminEmail}` + if not set. + ''; + }; + + allowRegistration = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Whether to allow new users to sign up. + ''; + }; + + secretsFile = mkOption { + type = types.str; + description = mdDoc '' + Path to the secret configuration file. + + See the Pleroma documentation for what this needs to contain. + ''; + }; }; } From 9175af418ee1ebd21bdb170d50a125609ac7e0d9 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 23:22:27 +0100 Subject: [PATCH 13/29] Document `resolved` module and options --- shared/resolved/default.nix | 6 ++ shared/resolved/options.nix | 111 ++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 12 deletions(-) diff --git a/shared/resolved/default.nix b/shared/resolved/default.nix index 41858486..c510e88a 100644 --- a/shared/resolved/default.nix +++ b/shared/resolved/default.nix @@ -1,3 +1,9 @@ +# [resolved][] is a recursive DNS server for LAN DNS. +# +# Enabling this module also provisions a [Grafana][] dashboard. +# +# [resolved]: https://github.com/barrucadu/resolved +# [Grafana]: https://grafana.com/ { config, lib, pkgs, ... }: with lib; diff --git a/shared/resolved/options.nix b/shared/resolved/options.nix index ad7bda04..a772f888 100644 --- a/shared/resolved/options.nix +++ b/shared/resolved/options.nix @@ -4,17 +4,104 @@ with lib; { options.nixfiles.resolved = { - enable = mkOption { type = types.bool; default = false; }; - address = mkOption { type = types.str; default = "0.0.0.0:53"; }; - metrics_address = mkOption { type = types.str; default = "127.0.0.1:9420"; }; - authoritative_only = mkOption { type = types.bool; default = false; }; - protocol_mode = mkOption { type = types.str; default = "only-v4"; }; - forward_address = mkOption { type = types.nullOr types.str; default = null; }; - cache_size = mkOption { type = types.int; default = 512; }; - hosts_dirs = mkOption { type = types.listOf types.str; default = [ ]; }; - zones_dirs = mkOption { type = types.listOf types.str; default = [ ]; }; - use_default_zones = mkOption { type = types.bool; default = true; }; - log_level = mkOption { type = types.str; default = "dns_resolver=info,resolved=info"; }; - log_format = mkOption { type = types.str; default = "json,no-time"; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the resolved service. + ''; + }; + + address = mkOption { + type = types.str; + default = "0.0.0.0:53"; + description = mdDoc '' + Address to listen on. + ''; + }; + + metrics_address = mkOption { + type = types.str; + default = "127.0.0.1:9420"; + description = mdDoc '' + Address to listen on to serve Prometheus metrics. + ''; + }; + + authoritative_only = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Only answer queries for which this server is authoritative: do not + perform recursive or forwarding resolution. + ''; + }; + + protocol_mode = mkOption { + type = types.str; + default = "only-v4"; + description = mdDoc '' + How to choose between connecting to upstream nameservers over IPv4 or + IPv6 when acting as a recursive resolver. + ''; + }; + + forward_address = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Act as a forwarding resolver, not a recursive resolver: forward queries + which can't be answered from local state to this nameserver and cache + the result. + ''; + }; + + cache_size = mkOption { + type = types.int; + default = 512; + description = mdDoc '' + How many records to hold in the cache. + ''; + }; + + hosts_dirs = mkOption { + type = types.listOf types.str; + default = [ ]; + description = mdDoc '' + List of directories to read hosts files from. + ''; + }; + + zones_dirs = mkOption { + type = types.listOf types.str; + default = [ ]; + description = mdDoc '' + List of directories to read zone files from. + ''; + }; + + use_default_zones = mkOption { + type = types.bool; + default = true; + description = mdDoc '' + Include the default zone files. + ''; + }; + + log_level = mkOption { + type = types.str; + default = "dns_resolver=info,resolved=info"; + description = mdDoc '' + Verbosity of the log messages. + ''; + }; + + log_format = mkOption { + type = types.str; + default = "json,no-time"; + description = mdDoc '' + Format of the log messages. + ''; + }; }; } From b4fd464243e1eb0cfdc98cfae64856dc9a7dddb2 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 23:29:51 +0100 Subject: [PATCH 14/29] Document `rtorrent` module and options --- shared/rtorrent/default.nix | 10 +++++ shared/rtorrent/options.nix | 87 ++++++++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/shared/rtorrent/default.nix b/shared/rtorrent/default.nix index a59a7443..afa907e7 100644 --- a/shared/rtorrent/default.nix +++ b/shared/rtorrent/default.nix @@ -1,3 +1,13 @@ +# [rTorrent][] is a bittorrent client. This module configures it in a way +# appropriate for private trackers. +# +# This module does not include a backup script. Torrented files must be backed +# up independently. +# +# If the `erase-your-darlings` module is enabled, stores the session data and +# logs on the persistent volume. +# +# [rTorrent]: https://github.com/rakshasa/rtorrent { config, lib, pkgs, ... }: with lib; diff --git a/shared/rtorrent/options.nix b/shared/rtorrent/options.nix index f17c4725..fd167610 100644 --- a/shared/rtorrent/options.nix +++ b/shared/rtorrent/options.nix @@ -4,19 +4,86 @@ with lib; { options.nixfiles.rtorrent = { - enable = mkOption { type = types.bool; default = false; }; - downloadDir = mkOption { type = types.str; }; - watchDir = mkOption { type = types.str; }; - user = mkOption { type = types.str; }; - logLevels = mkOption { type = types.listOf types.str; default = [ "info" ]; }; - openFirewall = mkOption { type = types.bool; default = true; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the rTorrent service. + ''; + }; + + downloadDir = mkOption { + type = types.str; + example = "/mnt/nas/torrents/files/"; + description = mdDoc '' + Directory to download torrented files to. + ''; + }; + + watchDir = mkOption { + type = types.str; + example = "/mnt/nas/torrents/watch/"; + description = mdDoc '' + Directory to monitor for new .torrent files. + ''; + }; + + user = mkOption { + type = types.str; + description = mdDoc '' + The user to run rTorrent as. + ''; + }; + + logLevels = mkOption { + type = types.listOf types.str; + default = [ "info" ]; + description = mdDoc '' + Verbosity of the log messages. + ''; + }; + + openFirewall = mkOption { + type = types.bool; + default = true; + description = mdDoc '' + Allow connections from TCP and UDP ports `''${portRange.from}` to + `''${portRange.to}`. + ''; + }; + portRange = { - from = mkOption { type = types.int; default = 50000; }; - to = mkOption { type = types.int; default = 50000; }; + from = mkOption { + type = types.int; + default = 50000; + description = mdDoc '' + Lower bound (inclusive) of the port range to accept connections on. + ''; + }; + to = mkOption { + type = types.int; + default = 50000; + description = mdDoc '' + Upper bound (inclusive) of the port range to accept connections on. + ''; + }; }; + flood = { - enable = mkOption { type = types.bool; default = true; }; - port = mkOption { type = types.int; default = 45904; }; + enable = mkOption { + type = types.bool; + default = true; + description = mdDoc '' + Enable the [flood](https://flood.js.org/) web UI. + ''; + }; + port = mkOption { + type = types.int; + default = 45904; + description = mdDoc '' + Port (on 127.0.0.1) to expose the flood service on. + ''; + }; }; }; } From cc5f1315eaf02fa5eb18977fe59efb2bf8089385 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Sun, 15 Oct 2023 23:41:35 +0100 Subject: [PATCH 15/29] Document `umami` module and options --- shared/umami/default.nix | 10 +++++++++ shared/umami/options.nix | 44 +++++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/shared/umami/default.nix b/shared/umami/default.nix index 12ad162b..ccfbb8e8 100644 --- a/shared/umami/default.nix +++ b/shared/umami/default.nix @@ -1,3 +1,13 @@ +# [umami][] is a web analytics tool. +# +# umami uses a containerised postgres database. +# +# If the `backups` module is enabled, adds a script to backup the database. +# +# If the `erase-your-darlings` module is enabled, stores its data on the +# persistent volume. +# +# [umami]: https://umami.is/ { config, lib, pkgs, ... }: with lib; diff --git a/shared/umami/options.nix b/shared/umami/options.nix index 23259cf1..e1b5f707 100644 --- a/shared/umami/options.nix +++ b/shared/umami/options.nix @@ -4,10 +4,44 @@ with lib; { options.nixfiles.umami = { - enable = mkOption { type = types.bool; default = false; }; - port = mkOption { type = types.int; default = 46489; }; - postgresTag = mkOption { type = types.str; default = "13"; }; - umamiTag = mkOption { type = types.str; default = "postgresql-latest"; }; - environmentFile = mkOption { type = types.str; }; + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the umami service. + ''; + }; + + port = mkOption { + type = types.int; + default = 46489; + description = mdDoc '' + Port (on 127.0.0.1) to expose umami on. + ''; + }; + + postgresTag = mkOption { + type = types.str; + default = "13"; + description = mdDoc '' + Tag to use of the `postgres` container image. + ''; + }; + + umamiTag = mkOption { + type = types.str; + default = "postgresql-latest"; + description = mdDoc '' + Tag to use of the `ghcr.io/mikecao/umami` container image. + ''; + }; + + environmentFile = mkOption { + type = types.str; + description = mdDoc '' + Environment file to be pased to the container. This needs to contain a + `HASH_SALT`. + ''; + }; }; } From 539a51283d71c80eef3af9ccad99e5f157da25ef Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:08:41 +0100 Subject: [PATCH 16/29] Document the `oci-containers` module and options --- shared/oci-containers/default.nix | 12 ++ shared/oci-containers/options.nix | 227 ++++++++++++++++++++++++++---- 2 files changed, 215 insertions(+), 24 deletions(-) diff --git a/shared/oci-containers/default.nix b/shared/oci-containers/default.nix index f9d460ef..c11057b2 100644 --- a/shared/oci-containers/default.nix +++ b/shared/oci-containers/default.nix @@ -1,3 +1,15 @@ +# An abstraction over running containers as systemd units, enforcing some good +# practices: +# +# - Container DNS behaves the same under docker and podman. +# - Ports are exposed on `127.0.0.1`, rather than `0.0.0.0`. +# - Volumes are backed up by bind-mounts to the host filesystem. +# +# Switching between using docker or podman for the container runtime should be +# totally transparent. +# +# If the `erase-your-darlings` module is enabled, stores volume bind-mounts on +# the persistent volume. { config, lib, pkgs, ... }: # TODO: ensure podman containers run as a non-root user diff --git a/shared/oci-containers/options.nix b/shared/oci-containers/options.nix index b411a4ed..b917cebf 100644 --- a/shared/oci-containers/options.nix +++ b/shared/oci-containers/options.nix @@ -3,62 +3,241 @@ with lib; let portOptions = { - host = mkOption { type = types.int; }; - inner = mkOption { type = types.int; }; + host = mkOption { + type = types.int; + description = mdDoc '' + Host port (on 127.0.0.1) to expose the inner port on. + ''; + }; + + inner = mkOption { + type = types.int; + description = mdDoc '' + Container port. + ''; + }; }; volumeOptions = { - name = mkOption { type = types.nullOr types.str; default = null; }; - host = mkOption { type = types.nullOr types.str; default = null; }; - inner = mkOption { type = types.str; }; + name = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Name of the volume. This creates a bind-mount to + `''${volumeBaseDir}/''${volumeSubDir}/''${name}`. + + Exactly one of this or `''${host}` must be specified. + ''; + }; + + host = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Directory on the host to bind-mount into the container. + + Exactly one of this or `''${name}` must be specified. + ''; + }; + + inner = mkOption { + type = types.str; + description = mdDoc '' + Directory in the container to mount the volume to. + ''; + }; }; containerOptions = { /* regular oci-containers */ - autoStart = mkOption { type = types.bool; default = true; }; - cmd = mkOption { type = types.listOf types.str; default = [ ]; }; - dependsOn = mkOption { type = types.listOf types.str; default = [ ]; }; - environment = mkOption { type = types.attrsOf types.str; default = { }; }; - environmentFiles = mkOption { type = types.listOf types.path; default = [ ]; }; - extraOptions = mkOption { type = types.listOf types.str; default = [ ]; }; - image = mkOption { type = types.str; }; - login.username = mkOption { type = types.nullOr types.str; default = null; }; - login.passwordFile = mkOption { type = types.nullOr types.str; default = null; }; - login.registry = mkOption { type = types.nullOr types.str; default = null; }; + autoStart = mkOption { + type = types.bool; + default = true; + description = mdDoc '' + Whether to start the container automatically on boot. + ''; + }; + + cmd = mkOption { + type = types.listOf types.str; + default = [ ]; + description = mdDoc '' + Command-line arguments to pass to the container image's entrypoint. + ''; + }; + + dependsOn = mkOption { + type = types.listOf types.str; + default = [ ]; + description = mdDoc '' + Other containers that this one depends on. + ''; + }; + + environment = mkOption { + type = types.attrsOf types.str; + default = { }; + description = mdDoc '' + Environment variables to set for this container. + ''; + }; + + environmentFiles = mkOption { + type = types.listOf types.path; + default = [ ]; + description = mdDoc '' + List of environment files for this container. + ''; + }; + + extraOptions = mkOption { + type = types.listOf types.str; + default = [ ]; + description = mdDoc '' + Extra options to pass to `docker run` / `podman run`. + ''; + }; + + image = mkOption { + type = types.str; + description = mdDoc '' + Container image to run. + ''; + }; + + login = { + username = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Username for the container registry. + ''; + }; + passwordFile = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + File containing the password for the container registry. + ''; + }; + registry = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Container registry to authenticate with. + ''; + }; + }; + /* changed */ - ports = mkOption { type = types.listOf (types.submodule { options = portOptions; }); default = [ ]; }; - volumes = mkOption { type = types.listOf (types.submodule { options = volumeOptions; }); default = [ ]; }; + ports = mkOption { + type = types.listOf (types.submodule { options = portOptions; }); + default = [ ]; + description = mdDoc '' + List of ports to expose. + ''; + }; + + volumes = mkOption { + type = types.listOf (types.submodule { options = volumeOptions; }); + default = [ ]; + description = mdDoc '' + List of volume definitions. + ''; + }; + /* new options */ - pullOnStart = mkOption { type = types.bool; default = true; }; + pullOnStart = mkOption { + type = types.bool; + default = true; + description = mdDoc '' + Whether to pull the container image when starting (useful for `:latest` + images). + ''; + }; }; in { options.nixfiles.oci-containers = { - backend = mkOption { type = types.enum [ "docker" "podman" ]; default = "docker"; }; + backend = mkOption { + type = types.enum [ "docker" "podman" ]; + default = "docker"; + description = mdDoc '' + The container runtime. + ''; + }; + containers = mkOption { type = types.attrsOf (types.submodule ({ name, ... }: { options = containerOptions // { - pod = mkOption { type = types.nullOr types.str; default = null; }; - network = mkOption { type = types.nullOr types.str; default = null; }; - volumeSubDir = mkOption { type = types.str; default = name; }; + pod = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Pod to attach the container to. This is only valid if using + podman as the backend. + ''; + }; + network = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + Network to attach the container to. This is only valid if using + docker as the backend. + ''; + }; + volumeSubDir = mkOption { + type = types.str; + default = name; + description = mdDoc '' + Subdirectory of the `''${volumeBaseDir}` to store bind-mounts + under. + ''; + }; }; })); default = { }; + description = mdDoc '' + Attrset of container definitions. + ''; }; + pods = mkOption { type = types.attrsOf (types.submodule ({ name, ... }: { options = { containers = mkOption { type = types.attrsOf (types.submodule { options = containerOptions; }); default = { }; + description = mdDoc '' + Attrset of container definitions. + ''; + }; + volumeSubDir = mkOption { + type = types.str; + default = name; + description = mdDoc '' + Subdirectory of the `''${volumeBaseDir}` to store bind-mounts + under. + ''; }; - volumeSubDir = mkOption { type = types.str; default = name; }; }; })); default = { }; + description = mdDoc '' + Attrset of pod definitions. + ''; + }; + + volumeBaseDir = mkOption { + type = types.str; + description = mdDoc '' + Directory to store volume bind-mounts under. + + If the `erase-your-darlings` module is enabled, this is overridden to be + on the persistent volume. + ''; }; - volumeBaseDir = mkOption { type = types.str; }; }; } From 6bdd1ef9b53d441bd64a5325c1d4d4ba2db65c71 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:10:35 +0100 Subject: [PATCH 17/29] Document the shared module and options --- shared/default.nix | 1 + shared/options.nix | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/shared/default.nix b/shared/default.nix index f6378564..701c056d 100644 --- a/shared/default.nix +++ b/shared/default.nix @@ -1,3 +1,4 @@ +# Common configuration enabled on all hosts. { config, lib, pkgs, flakeInputs, ... }: with lib; diff --git a/shared/options.nix b/shared/options.nix index 3a5fa8ab..68aefc71 100644 --- a/shared/options.nix +++ b/shared/options.nix @@ -4,6 +4,12 @@ with lib; { options.nixfiles.firewall = { - ipBlocklistFile = mkOption { type = types.nullOr types.str; default = null; }; + ipBlocklistFile = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + File containing IPs to block. + ''; + }; }; } From 339acfefb9aec0199a885dfea9f063aea73285e8 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:11:34 +0100 Subject: [PATCH 18/29] Enforce options have descriptions --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index a719182d..beb33eb3 100644 --- a/flake.nix +++ b/flake.nix @@ -112,7 +112,6 @@ }; optionsDoc = pkgs.nixosOptionsDoc { options = eval.options; - warningsAreErrors = false; }; in mkApp "documentation" '' From adfdd305fb3090f4a0b4df319dd36b886e28ddc8 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:14:42 +0100 Subject: [PATCH 19/29] Rename `resolved` options for consistency --- hosts/nyarlathotep/configuration.nix | 6 +++--- shared/resolved/default.nix | 22 +++++++++++----------- shared/resolved/options.nix | 20 ++++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/hosts/nyarlathotep/configuration.nix b/hosts/nyarlathotep/configuration.nix index 648df8e8..7f54bbfe 100644 --- a/hosts/nyarlathotep/configuration.nix +++ b/hosts/nyarlathotep/configuration.nix @@ -60,9 +60,9 @@ in ############################################################################### nixfiles.resolved.enable = true; - nixfiles.resolved.cache_size = 1000000; - nixfiles.resolved.hosts_dirs = [ "/etc/dns/hosts" ]; - nixfiles.resolved.zones_dirs = [ "/etc/dns/zones" ]; + nixfiles.resolved.cacheSize = 1000000; + nixfiles.resolved.hostsDirs = [ "/etc/dns/hosts" ]; + nixfiles.resolved.zonesDirs = [ "/etc/dns/zones" ]; environment.etc."dns/hosts/stevenblack".source = builtins.fetchurl { url = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"; diff --git a/shared/resolved/default.nix b/shared/resolved/default.nix index c510e88a..886b3648 100644 --- a/shared/resolved/default.nix +++ b/shared/resolved/default.nix @@ -25,22 +25,22 @@ in ExecStart = concatStringsSep " " [ "${pkgs.nixfiles.resolved}/bin/resolved" "-i ${cfg.address}" - "-s ${toString cfg.cache_size}" - "--metrics-address ${cfg.metrics_address}" - "--protocol-mode ${cfg.protocol_mode}" - (if cfg.authoritative_only then "--authoritative-only " else "") - (if cfg.forward_address != null then "--forward-address ${cfg.forward_address} " else "") - (if cfg.hosts_dirs == [ ] then "" else "-A ${concatStringsSep " -A " cfg.hosts_dirs}") - (if cfg.use_default_zones then "-Z ${pkgs.nixfiles.resolved}/etc/resolved/zones" else "") - (if cfg.zones_dirs == [ ] then "" else "-Z ${concatStringsSep " -Z " cfg.zones_dirs}") + "-s ${toString cfg.cacheSize}" + "--metrics-address ${cfg.metricsAddress}" + "--protocol-mode ${cfg.protocolMode}" + (if cfg.authoritativeOnly then "--authoritative-only " else "") + (if cfg.forwardAddress != null then "--forward-address ${cfg.forwardAddress} " else "") + (if cfg.hostsDirs == [ ] then "" else "-A ${concatStringsSep " -A " cfg.hostsDirs}") + (if cfg.useDefaultZones then "-Z ${pkgs.nixfiles.resolved}/etc/resolved/zones" else "") + (if cfg.zonesDirs == [ ] then "" else "-Z ${concatStringsSep " -Z " cfg.zonesDirs}") ]; ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID"; DynamicUser = "true"; Restart = "on-failure"; }; environment = { - RUST_LOG = cfg.log_level; - RUST_LOG_FORMAT = cfg.log_format; + RUST_LOG = cfg.logLevel; + RUST_LOG_FORMAT = cfg.logFormat; }; }; @@ -50,7 +50,7 @@ in services.prometheus.scrapeConfigs = [ { job_name = "${config.networking.hostName}-resolved"; - static_configs = [{ targets = [ cfg.metrics_address ]; }]; + static_configs = [{ targets = [ cfg.metricsAddress ]; }]; } ]; services.grafana.provision.dashboards.settings.providers = diff --git a/shared/resolved/options.nix b/shared/resolved/options.nix index a772f888..ecd9c8a9 100644 --- a/shared/resolved/options.nix +++ b/shared/resolved/options.nix @@ -20,7 +20,7 @@ with lib; ''; }; - metrics_address = mkOption { + metricsAddress = mkOption { type = types.str; default = "127.0.0.1:9420"; description = mdDoc '' @@ -28,7 +28,7 @@ with lib; ''; }; - authoritative_only = mkOption { + authoritativeOnly = mkOption { type = types.bool; default = false; description = mdDoc '' @@ -37,7 +37,7 @@ with lib; ''; }; - protocol_mode = mkOption { + protocolMode = mkOption { type = types.str; default = "only-v4"; description = mdDoc '' @@ -46,7 +46,7 @@ with lib; ''; }; - forward_address = mkOption { + forwardAddress = mkOption { type = types.nullOr types.str; default = null; description = mdDoc '' @@ -56,7 +56,7 @@ with lib; ''; }; - cache_size = mkOption { + cacheSize = mkOption { type = types.int; default = 512; description = mdDoc '' @@ -64,7 +64,7 @@ with lib; ''; }; - hosts_dirs = mkOption { + hostsDirs = mkOption { type = types.listOf types.str; default = [ ]; description = mdDoc '' @@ -72,7 +72,7 @@ with lib; ''; }; - zones_dirs = mkOption { + zonesDirs = mkOption { type = types.listOf types.str; default = [ ]; description = mdDoc '' @@ -80,7 +80,7 @@ with lib; ''; }; - use_default_zones = mkOption { + useDefaultZones = mkOption { type = types.bool; default = true; description = mdDoc '' @@ -88,7 +88,7 @@ with lib; ''; }; - log_level = mkOption { + logLevel = mkOption { type = types.str; default = "dns_resolver=info,resolved=info"; description = mdDoc '' @@ -96,7 +96,7 @@ with lib; ''; }; - log_format = mkOption { + logFormat = mkOption { type = types.str; default = "json,no-time"; description = mdDoc '' From dddeae2b4ea8a24bded2cc0fdfb9c3d7b2e9d81e Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:15:31 +0100 Subject: [PATCH 20/29] Rename `pleroma.pgTag` for consistency --- shared/pleroma/default.nix | 2 +- shared/pleroma/options.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/pleroma/default.nix b/shared/pleroma/default.nix index 2614b220..103b0df9 100644 --- a/shared/pleroma/default.nix +++ b/shared/pleroma/default.nix @@ -78,7 +78,7 @@ in }; nixfiles.oci-containers.containers.pleroma-db = { - image = "postgres:${cfg.pgTag}"; + image = "postgres:${cfg.postgresTag}"; environment = { "POSTGRES_DB" = "pleroma"; "POSTGRES_USER" = "pleroma"; diff --git a/shared/pleroma/options.nix b/shared/pleroma/options.nix index 3f365480..61bb0eab 100644 --- a/shared/pleroma/options.nix +++ b/shared/pleroma/options.nix @@ -20,7 +20,7 @@ with lib; ''; }; - pgTag = mkOption { + postgresTag = mkOption { type = types.str; default = "13"; description = mdDoc '' From ffc61366bf13e2f59c2c51327b92ed5529f5507e Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:18:17 +0100 Subject: [PATCH 21/29] Rename `*.esTag` for consistency --- shared/bookdb/default.nix | 2 +- shared/bookdb/options.nix | 2 +- shared/bookmarks/default.nix | 2 +- shared/bookmarks/options.nix | 2 +- shared/finder/default.nix | 2 +- shared/finder/options.nix | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/shared/bookdb/default.nix b/shared/bookdb/default.nix index b6751c35..d851faff 100644 --- a/shared/bookdb/default.nix +++ b/shared/bookdb/default.nix @@ -47,7 +47,7 @@ in }; nixfiles.oci-containers.containers.bookdb-db = { - image = "elasticsearch:${cfg.esTag}"; + image = "elasticsearch:${cfg.elasticsearchTag}"; environment = { "http.host" = "0.0.0.0"; "discovery.type" = "single-node"; diff --git a/shared/bookdb/options.nix b/shared/bookdb/options.nix index 615e41d1..3d9c7683 100644 --- a/shared/bookdb/options.nix +++ b/shared/bookdb/options.nix @@ -28,7 +28,7 @@ with lib; ''; }; - esTag = mkOption { + elasticsearchTag = mkOption { type = types.str; default = "8.0.0"; description = mdDoc '' diff --git a/shared/bookmarks/default.nix b/shared/bookmarks/default.nix index a19e55d8..2a858488 100644 --- a/shared/bookmarks/default.nix +++ b/shared/bookmarks/default.nix @@ -42,7 +42,7 @@ in }; nixfiles.oci-containers.containers.bookmarks-db = { - image = "elasticsearch:${cfg.esTag}"; + image = "elasticsearch:${cfg.elasticsearchTag}"; environment = { "http.host" = "0.0.0.0"; "discovery.type" = "single-node"; diff --git a/shared/bookmarks/options.nix b/shared/bookmarks/options.nix index 66fdb6bc..2fe98d78 100644 --- a/shared/bookmarks/options.nix +++ b/shared/bookmarks/options.nix @@ -28,7 +28,7 @@ with lib; ''; }; - esTag = mkOption { + elasticsearchTag = mkOption { type = types.str; default = "8.0.0"; description = mdDoc '' diff --git a/shared/finder/default.nix b/shared/finder/default.nix index a7b7a2e8..0393b88f 100644 --- a/shared/finder/default.nix +++ b/shared/finder/default.nix @@ -32,7 +32,7 @@ in }; db = { - image = "elasticsearch:${cfg.esTag}"; + image = "elasticsearch:${cfg.elasticsearchTag}"; environment = { "http.host" = "0.0.0.0"; "discovery.type" = "single-node"; diff --git a/shared/finder/options.nix b/shared/finder/options.nix index 6be42403..7b849969 100644 --- a/shared/finder/options.nix +++ b/shared/finder/options.nix @@ -27,7 +27,7 @@ with lib; ''; }; - esTag = mkOption { + elasticsearchTag = mkOption { type = types.str; default = "8.0.0"; description = mdDoc '' From 4b18a046bbcfa5839687ff35e020396d336cf0ee Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:20:07 +0100 Subject: [PATCH 22/29] Rename `*.esPort` for consistency --- shared/bookdb/default.nix | 4 ++-- shared/bookdb/options.nix | 2 +- shared/bookmarks/default.nix | 6 +++--- shared/bookmarks/options.nix | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/shared/bookdb/default.nix b/shared/bookdb/default.nix index d851faff..856c7ea0 100644 --- a/shared/bookdb/default.nix +++ b/shared/bookdb/default.nix @@ -41,7 +41,7 @@ in "ALLOW_WRITES" = if cfg.readOnly then "0" else "1"; "BASE_URI" = cfg.baseURI; "COVER_DIR" = "${cfg.dataDir}/covers"; - "ES_HOST" = "http://127.0.0.1:${toString cfg.esPort}"; + "ES_HOST" = "http://127.0.0.1:${toString cfg.elasticsearchPort}"; "UUIDS_FILE" = ./uuids.yaml; }; }; @@ -54,7 +54,7 @@ in "xpack.security.enabled" = "false"; "ES_JAVA_OPTS" = "-Xms512M -Xmx512M"; }; - ports = [{ host = cfg.esPort; inner = 9200; }]; + ports = [{ host = cfg.elasticsearchPort; inner = 9200; }]; volumes = [{ name = "esdata"; inner = "/usr/share/elasticsearch/data"; }]; volumeSubDir = "bookdb"; }; diff --git a/shared/bookdb/options.nix b/shared/bookdb/options.nix index 3d9c7683..df9b360c 100644 --- a/shared/bookdb/options.nix +++ b/shared/bookdb/options.nix @@ -20,7 +20,7 @@ with lib; ''; }; - esPort = mkOption { + elasticsearchPort = mkOption { type = types.int; default = 47164; description = mdDoc '' diff --git a/shared/bookmarks/default.nix b/shared/bookmarks/default.nix index 2a858488..4c3458cd 100644 --- a/shared/bookmarks/default.nix +++ b/shared/bookmarks/default.nix @@ -37,7 +37,7 @@ in environment = { ALLOW_WRITES = if cfg.readOnly then "0" else "1"; BASE_URI = cfg.baseURI; - ES_HOST = "http://127.0.0.1:${toString cfg.esPort}"; + ES_HOST = "http://127.0.0.1:${toString cfg.elasticsearchPort}"; }; }; @@ -49,13 +49,13 @@ in "xpack.security.enabled" = "false"; "ES_JAVA_OPTS" = "-Xms512M -Xmx512M"; }; - ports = [{ host = cfg.esPort; inner = 9200; }]; + ports = [{ host = cfg.elasticsearchPort; inner = 9200; }]; volumes = [{ name = "esdata"; inner = "/usr/share/elasticsearch/data"; }]; volumeSubDir = "bookmarks"; }; nixfiles.backups.scripts.bookmarks = '' - env ES_HOST=http://127.0.0.1:${toString cfg.esPort} ${pkgs.nixfiles.bookmarks}/bin/python -m bookmarks.index.dump | gzip -9 > dump.json.gz + env ES_HOST=http://127.0.0.1:${toString cfg.elasticsearchPort} ${pkgs.nixfiles.bookmarks}/bin/python -m bookmarks.index.dump | gzip -9 > dump.json.gz ''; }; } diff --git a/shared/bookmarks/options.nix b/shared/bookmarks/options.nix index 2fe98d78..60d5a3f4 100644 --- a/shared/bookmarks/options.nix +++ b/shared/bookmarks/options.nix @@ -20,7 +20,7 @@ with lib; ''; }; - esPort = mkOption { + elasticsearchPort = mkOption { type = types.int; default = 43389; description = mdDoc '' From c957dec8269891ea04a45f7c90b3da791fe92c2d Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:25:22 +0100 Subject: [PATCH 23/29] Remove legacy `oci-containers.containers` options --- shared/bookdb/default.nix | 3 +-- shared/bookmarks/default.nix | 3 +-- shared/oci-containers/default.nix | 3 +-- shared/oci-containers/options.nix | 37 ------------------------------- shared/pleroma/default.nix | 3 +-- 5 files changed, 4 insertions(+), 45 deletions(-) diff --git a/shared/bookdb/default.nix b/shared/bookdb/default.nix index 856c7ea0..a209e401 100644 --- a/shared/bookdb/default.nix +++ b/shared/bookdb/default.nix @@ -46,7 +46,7 @@ in }; }; - nixfiles.oci-containers.containers.bookdb-db = { + nixfiles.oci-containers.pods.bookdb.containers.db = { image = "elasticsearch:${cfg.elasticsearchTag}"; environment = { "http.host" = "0.0.0.0"; @@ -56,7 +56,6 @@ in }; ports = [{ host = cfg.elasticsearchPort; inner = 9200; }]; volumes = [{ name = "esdata"; inner = "/usr/share/elasticsearch/data"; }]; - volumeSubDir = "bookdb"; }; users.users.bookdb = { diff --git a/shared/bookmarks/default.nix b/shared/bookmarks/default.nix index 4c3458cd..cdfe89f9 100644 --- a/shared/bookmarks/default.nix +++ b/shared/bookmarks/default.nix @@ -41,7 +41,7 @@ in }; }; - nixfiles.oci-containers.containers.bookmarks-db = { + nixfiles.oci-containers.pods.bookmarks.containers.db = { image = "elasticsearch:${cfg.elasticsearchTag}"; environment = { "http.host" = "0.0.0.0"; @@ -51,7 +51,6 @@ in }; ports = [{ host = cfg.elasticsearchPort; inner = 9200; }]; volumes = [{ name = "esdata"; inner = "/usr/share/elasticsearch/data"; }]; - volumeSubDir = "bookmarks"; }; nixfiles.backups.scripts.bookmarks = '' diff --git a/shared/oci-containers/default.nix b/shared/oci-containers/default.nix index c11057b2..a3f5c1f2 100644 --- a/shared/oci-containers/default.nix +++ b/shared/oci-containers/default.nix @@ -93,9 +93,8 @@ let volumeSubDir = pod.volumeSubDir; } ); - podContainers = concatMapAttrs (podName: pod: mapAttrs' (mkPodContainer podName pod) pod.containers) cfg.pods; in - attrsets.unionOfDisjoint cfg.containers podContainers; + concatMapAttrs (podName: pod: mapAttrs' (mkPodContainer podName pod) pod.containers) cfg.pods; in { imports = [ diff --git a/shared/oci-containers/options.nix b/shared/oci-containers/options.nix index b917cebf..333a8cc3 100644 --- a/shared/oci-containers/options.nix +++ b/shared/oci-containers/options.nix @@ -167,43 +167,6 @@ in ''; }; - containers = mkOption { - type = types.attrsOf (types.submodule ({ name, ... }: { - options = - containerOptions // - { - pod = mkOption { - type = types.nullOr types.str; - default = null; - description = mdDoc '' - Pod to attach the container to. This is only valid if using - podman as the backend. - ''; - }; - network = mkOption { - type = types.nullOr types.str; - default = null; - description = mdDoc '' - Network to attach the container to. This is only valid if using - docker as the backend. - ''; - }; - volumeSubDir = mkOption { - type = types.str; - default = name; - description = mdDoc '' - Subdirectory of the `''${volumeBaseDir}` to store bind-mounts - under. - ''; - }; - }; - })); - default = { }; - description = mdDoc '' - Attrset of container definitions. - ''; - }; - pods = mkOption { type = types.attrsOf (types.submodule ({ name, ... }: { options = { diff --git a/shared/pleroma/default.nix b/shared/pleroma/default.nix index 103b0df9..9e909a7d 100644 --- a/shared/pleroma/default.nix +++ b/shared/pleroma/default.nix @@ -77,7 +77,7 @@ in [ "${toString (pkgs.copyPathToStore cfg.faviconPath)}:/var/lib/pleroma/static/favicon.png" ]; }; - nixfiles.oci-containers.containers.pleroma-db = { + nixfiles.oci-containers.pods.pleroma.containers.db = { image = "postgres:${cfg.postgresTag}"; environment = { "POSTGRES_DB" = "pleroma"; @@ -89,7 +89,6 @@ in { name = "pgdata"; inner = "/var/lib/postgresql/data"; } { host = "/var/run/pleroma/db"; inner = "/var/run/postgresql"; } ]; - volumeSubDir = "pleroma"; }; # TODO: figure out how to get `sudo` in the unit's path (adding the package From 06c4a969b9102d55f14fbb02295dee975112e0b1 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:36:11 +0100 Subject: [PATCH 24/29] Most host documentation out of README --- README.markdown | 47 ---------------------------- docs/.gitignore | 1 + docs/src/SUMMARY.md | 1 + hosts/azathoth/configuration.nix | 13 ++++++++ hosts/carcosa/configuration.nix | 19 +++++++++++ hosts/nyarlathotep/configuration.nix | 17 ++++++++++ scripts/documentation.sh | 26 +++++++++++++++ 7 files changed, 77 insertions(+), 47 deletions(-) diff --git a/README.markdown b/README.markdown index 8577afc9..79b68277 100644 --- a/README.markdown +++ b/README.markdown @@ -65,53 +65,6 @@ default. [wiping `/` on boot]: https://grahamc.com/blog/erase-your-darlings -### Hosts - -Currently I have 3 NixOS machines. The naming convention is: - -- **Local machines:** beings (gods, people, etc) of the Cthulhu Mythos. -- **Remote machines:** places of the Cthulhu Mythos. - -#### azathoth - -This is my desktop computer. - -It dual-boots Windows and NixOS, so it doesn’t run any services, as they won't -be accessible half of the time. I don't bother backing up either OS: everything -I care about is in Syncthing, on GitHub, or on some other cloud service (eg, -Steam). - -#### carcosa - -This is a VPS (hosted by Hetzner Cloud). - -It serves [barrucadu.co.uk][] and other services on it, such as [a bookdb -instance][] and [my blog][]. Websites are served with Caddy, with certs from -Let's Encrypt. - -It's set up in "erase your darlings" style, so most of the filesystem is wiped -on boot and restored from the configuration, to ensure there's no accidentally -unmanaged configuration or state hanging around. However, it doesn't reboot -automatically, because I also use this server for a persistent IRC connection. - -[barrucadu.co.uk]: https://www.barrucadu.co.uk/ -[a bookdb instance]: https://bookdb.barrucadu.co.uk/ -[my blog]: https://memo.barrucadu.co.uk/ - -#### nyarlathotep - -This is my home server. - -It runs writable instances of the bookdb and bookmarks services, which have any -updates copied across to carcosa hourly; it acts as a NAS; and it runs a few -utility services, such as a dashboard of finance information from my hledger -journal, and a script to automatically tag and organise new podcast episodes or -CD rips which I copy over to it. - -Like carcosa, this host is set up in "erase your darlings" style but, unlike -carcosa, it automatically reboots to install updates: so that takes effect -significantly more frequently. - Setting up a new host --------------------- diff --git a/docs/.gitignore b/docs/.gitignore index 5b2a6158..50006955 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -2,6 +2,7 @@ book # generated by the build script src/README.md +src/hosts.md src/modules.md src/options.md mdbook-admonish.css diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index bd2aa934..e95af39c 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -4,5 +4,6 @@ # Reference +- [Hosts](./hosts.md) - [Modules](./modules.md) - [Options](./options.md) diff --git a/hosts/azathoth/configuration.nix b/hosts/azathoth/configuration.nix index e9e59aa6..82e315a6 100644 --- a/hosts/azathoth/configuration.nix +++ b/hosts/azathoth/configuration.nix @@ -1,3 +1,16 @@ +# This is my desktop computer. +# +# It dual-boots Windows and NixOS. I don't bother backing up either OS: +# everything I care about is in Syncthing, on GitHub, or on some other cloud +# service (eg, Steam). +# +# **Alerting:** disabled +# +# **Backups:** disabled +# +# **Public hostname:** n/a +# +# **Role:** desktop { pkgs, ... }: let nfsShare = name: diff --git a/hosts/carcosa/configuration.nix b/hosts/carcosa/configuration.nix index 1ee60fe9..2b6f109a 100644 --- a/hosts/carcosa/configuration.nix +++ b/hosts/carcosa/configuration.nix @@ -1,3 +1,22 @@ +# This is a VPS (hosted by Hetzner Cloud). +# +# It serves [barrucadu.co.uk][] and other services on it. Websites are served +# with Caddy, with certs from Let's Encrypt. +# +# It's set up in "erase your darlings" style, so most of the filesystem is wiped +# on boot and restored from the configuration, to ensure there's no accidentally +# unmanaged configuration or state hanging around. However, it doesn't reboot +# automatically, because I also use this server for a persistent IRC connection. +# +# **Alerting:** enabled (standard only) +# +# **Backups:** enabled (standard + extras) +# +# **Public hostname:** `carcosa.barrucadu.co.uk` +# +# **Role:** server +# +# [barrucadu.co.uk]: https://www.barrucadu.co.uk/ { config, lib, pkgs, ... }: with lib; diff --git a/hosts/nyarlathotep/configuration.nix b/hosts/nyarlathotep/configuration.nix index 7f54bbfe..04fde39e 100644 --- a/hosts/nyarlathotep/configuration.nix +++ b/hosts/nyarlathotep/configuration.nix @@ -1,3 +1,20 @@ +# This is my home server. +# +# It runs writable instances of the bookdb and bookmarks services, which have +# any updates copied across to carcosa hourly; it acts as a NAS; and it runs a +# few utility services. +# +# Like carcosa, this host is set up in "erase your darlings" style but, unlike +# carcosa, it automatically reboots to install updates: so that takes effect +# significantly more frequently. +# +# **Alerting:** enabled (standard only) +# +# **Backups:** enabled (standard + extras) +# +# **Public hostname:** n/a +# +# **Role:** server { config, pkgs, lib, ... }: # Bring names from 'lib' into scope. diff --git a/scripts/documentation.sh b/scripts/documentation.sh index 6863c337..6e002d7e 100644 --- a/scripts/documentation.sh +++ b/scripts/documentation.sh @@ -6,6 +6,32 @@ popd cp README.markdown docs/src/README.md +python3 - <<'EOF' > docs/src/hosts.md +import os + +print("# Hosts") +print("") + +hosts = sorted([name for name in os.listdir("hosts") if name not in [".", ".."]]) +for host in hosts: + source_file = f"hosts/{host}/configuration.nix" + + print(f"## {host}") + + has_doc = False + with open(source_file, "r") as f: + for line in f: + if line.startswith("#"): + has_doc = True + print(line[1:].strip()) + else: + break + if not has_doc: + print("This host has no description.") + print(f"\n**Declared in:** [{source_file}](https://github.com/barrucadu/nixfiles/blob/master/{source_file})") + print("") +EOF + python3 - <<'EOF' > docs/src/modules.md import json import os From 8c3f92fcb0ddacd6372bd654a40afd31902f4141 Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:42:59 +0100 Subject: [PATCH 25/29] Document packages --- docs/.gitignore | 1 + docs/src/SUMMARY.md | 1 + packages/bookdb/default.nix | 11 ++++-- packages/bookmarks/default.nix | 11 ++++-- .../prometheus-awair-exporter/default.nix | 18 ++++++---- packages/resolved/default.nix | 18 ++++++---- scripts/documentation.sh | 34 +++++++++++++++++++ 7 files changed, 76 insertions(+), 18 deletions(-) diff --git a/docs/.gitignore b/docs/.gitignore index 50006955..36948ce0 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -5,4 +5,5 @@ src/README.md src/hosts.md src/modules.md src/options.md +src/packages.md mdbook-admonish.css diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index e95af39c..f3e8a9ba 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -7,3 +7,4 @@ - [Hosts](./hosts.md) - [Modules](./modules.md) - [Options](./options.md) +- [Packages](./packages.md) diff --git a/packages/bookdb/default.nix b/packages/bookdb/default.nix index ab55ec9b..d0abe966 100644 --- a/packages/bookdb/default.nix +++ b/packages/bookdb/default.nix @@ -1,11 +1,16 @@ +# A database and web app to keep track of all my books. { poetry2nix, fetchFromGitHub, ... }: let + githubOwner = "barrucadu"; + githubRepo = "bookdb"; + githubRev = "6040d270ae7ac7ecec09849885b6405d0650dff2"; + app = poetry2nix.mkPoetryApplication { projectDir = fetchFromGitHub { - owner = "barrucadu"; - repo = "bookdb"; - rev = "6040d270ae7ac7ecec09849885b6405d0650dff2"; + owner = githubOwner; + repo = githubRepo; + rev = githubRev; sha256 = "sha256-U93t2dbGjBej6+IsI2mUVqm0Sirw/DIJqYH0USUF7to="; }; diff --git a/packages/bookmarks/default.nix b/packages/bookmarks/default.nix index 35537755..07d4a178 100644 --- a/packages/bookmarks/default.nix +++ b/packages/bookmarks/default.nix @@ -1,11 +1,16 @@ +# A database and web app to keep track of my bookmarks. { poetry2nix, fetchFromGitHub, ... }: let + githubOwner = "barrucadu"; + githubRepo = "bookmarks"; + githubRev = "afe9c2a59c1e9d385074e17d684ac0ae7556fced"; + app = poetry2nix.mkPoetryApplication { projectDir = fetchFromGitHub { - owner = "barrucadu"; - repo = "bookmarks"; - rev = "afe9c2a59c1e9d385074e17d684ac0ae7556fced"; + owner = githubOwner; + repo = githubRepo; + rev = githubRev; sha256 = "sha256-uSsycnSWpIBc7SojptIgvjLkoZ0gTScelfygLJ9zvxI="; }; diff --git a/packages/prometheus-awair-exporter/default.nix b/packages/prometheus-awair-exporter/default.nix index aac1bb94..054ed90f 100644 --- a/packages/prometheus-awair-exporter/default.nix +++ b/packages/prometheus-awair-exporter/default.nix @@ -1,13 +1,19 @@ +# A simple Awair exporter for Prometheus. { buildGoModule, fetchFromGitHub, ... }: -buildGoModule rec { - pname = "prometheus-awair-exporter"; - version = "87c534bc15a10d1a1158aa543e467a2e0e175bd1"; +let + githubOwner = "barrucadu"; + githubRepo = "prometheus-awair-exporter"; + githubRev = "87c534bc15a10d1a1158aa543e467a2e0e175bd1"; +in +buildGoModule { + pname = githubRepo; + version = githubRev; src = fetchFromGitHub { - owner = "barrucadu"; - repo = pname; - rev = version; + owner = githubOwner; + repo = githubRepo; + rev = githubRev; sha256 = "sha256-v3VRECer+zTcLiS8sRXgWZMwQMNv8vyZeryJ4/XOKhQ="; }; diff --git a/packages/resolved/default.nix b/packages/resolved/default.nix index b96d6ab6..892fbd67 100644 --- a/packages/resolved/default.nix +++ b/packages/resolved/default.nix @@ -1,13 +1,19 @@ +# A simple DNS server for home networks. { rustPlatform, fetchFromGitHub, ... }: -rustPlatform.buildRustPackage rec { - pname = "resolved"; - version = "cc43b526dea18825288fa03a0c4a3ce98f053856"; +let + githubOwner = "barrucadu"; + githubRepo = "resolved"; + githubRev = "cc43b526dea18825288fa03a0c4a3ce98f053856"; +in +rustPlatform.buildRustPackage { + pname = githubRepo; + version = githubRev; src = fetchFromGitHub { - owner = "barrucadu"; - repo = pname; - rev = version; + owner = githubOwner; + repo = githubRepo; + rev = githubRev; sha256 = "sha256-gox2b9bqerH0rgC3CvJedvW1vP1vMpDZwKpHBWHQK7E="; }; diff --git a/scripts/documentation.sh b/scripts/documentation.sh index 6e002d7e..fc3dc7b7 100644 --- a/scripts/documentation.sh +++ b/scripts/documentation.sh @@ -104,6 +104,40 @@ for option in sorted(options.keys()): print("") EOF +python3 - <<'EOF' > docs/src/packages.md +import os + +print("# Packages") +print("") + +packages = sorted([name for name in os.listdir("packages") if name not in [".", ".."]]) +for package in packages: + source_file = f"packages/{package}/default.nix" + + print(f"## {package}") + + has_doc = False + doc = True + github = {} + with open(source_file, "r") as f: + for line in f: + if doc: + if line.startswith("#"): + has_doc = True + print(line[1:].strip()) + else: + doc = False + elif line.strip().startswith("github"): + prefix, suffix = line.split("=") + github[prefix.strip().removeprefix("github").lower()] = suffix.split('"')[1] + if not has_doc: + print("This package has no description.") + github_name = f"{github['owner']}/{github['repo']}" + print(f"\n**Source:** [{github_name}](https://github.com/{github_name}) @ [`{github['rev'][:7]}`](https://github.com/{github_name}/tree/{github['rev']})") + print(f"\n**Declared in:** [{source_file}](https://github.com/barrucadu/nixfiles/blob/master/{source_file})") + print("") +EOF + mdbook build docs mv docs/book _site From 9cc0d52422739c9ad54f3c8982b305abbc8964ea Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 16 Oct 2023 00:49:04 +0100 Subject: [PATCH 26/29] Move "Setting up a new host" out of the README --- README.markdown | 159 --------------------- docs/src/SUMMARY.md | 4 + docs/src/runbooks/set-up-a-new-host.md | 189 +++++++++++++++++++++++++ shared/erase-your-darlings/default.nix | 3 +- 4 files changed, 195 insertions(+), 160 deletions(-) create mode 100644 docs/src/runbooks/set-up-a-new-host.md diff --git a/README.markdown b/README.markdown index 79b68277..6eea0cce 100644 --- a/README.markdown +++ b/README.markdown @@ -66,165 +66,6 @@ default. [wiping `/` on boot]: https://grahamc.com/blog/erase-your-darlings -Setting up a new host ---------------------- - -See also [the NixOS installation instructions](https://nixos.org/manual/nixos/stable/index.html#ch-installation). - -1. Create & format partitions -1. **Optional:** Configure wiping / on boot (pre-first-boot steps) -1. Install NixOS with the standard installer -1. Reboot into the installed system -1. Clone this repo to `/etc/nixos` -1. Move the generated configuration to `hosts//` and edit to fit repo conventions -1. Add an entry for the host to `flake.nix` -1. **Optional:** Add DNS records -1. **Optional:** Configure secrets -1. **Optional:** Configure wiping / on boot (post-first-boot steps) -1. **Optional:** Configure backups -1. **Optional:** Generate SSH key -1. Build the new system configuration with `sudo nixos-rebuild switch --flake '.#'` -1. Reboot -1. Commit, push, & merge - -### Optional: Configure wiping / on boot - -Before installing NixOS, create the `local` pool and datasets: - -```bash -zpool create -o mountpoint=legacy -o autotrim=on local - -zfs create -o mountpoint=legacy local/volatile -zfs create -o mountpoint=legacy local/volatile/root - -zfs create -o mountpoint=legacy local/persistent -zfs create -o mountpoint=legacy -o com.sun:auto-snapshot=true local/persistent/home -zfs create -o mountpoint=legacy -o com.sun:auto-snapshot=true local/persistent/nix -zfs create -o mountpoint=legacy -o com.sun:auto-snapshot=true local/persistent/persist -zfs create -o mountpoint=legacy -o com.sun:auto-snapshot=true local/persistent/var-log -``` - -Take a snapshot of the empty root dataset: - -```bash -zfs snapshot local/volatile/root@blank -``` - -Mount all the filesystems under `/mnt`: - -```bash -mount -t zfs local/volatile/root /mnt - -mkdir /mnt/boot -mkdir /mnt/home -mkdir /mnt/nix -mkdir /mnt/persist -mkdir -p /mnt/var/log - -mount /dev/ /mnt/boot -mount -t zfs local/persistent/home /mnt/home -mount -t zfs local/persistent/nix /mnt/nix -mount -t zfs local/persistent/persist /mnt/persist -mount -t zfs local/persistent/var-log /mnt/var/log -``` - -Then run the installer, making sure to add ZFS details to the generated configuration: - -```nix -networking.hostId = ""; -boot.supportedFilesystems = [ "zfs" ]; -``` - -**After first boot:** copy any needed files (eg, SSH host keys) to the -appropriate place in `/persist`, add the user password to the secrets, and set -up `nixfiles.eraseYourDarlings`: - -```nix -nixfiles.eraseYourDarlings.enable = true; -nixfiles.eraseYourDarlings.machineId = ""; -nixfiles.eraseYourDarlings.barrucaduPasswordFile = config.sops.secrets."users/barrucadu".path; -sops.secrets."users/barrucadu".neededForUsers = true; -``` - -### Optional: Add DNS records - -Add `A` / `AAAA` records to [the ops repo](https://github.com/barrucadu/ops) and -apply the change via [Concourse](https://cd.barrucadu.dev/). - -### Optional: Configure secrets - -After first boot, generate an age public key from the host SSH key: - -```bash -nix-shell -p ssh-to-age --run 'ssh-keyscan .barrucadu.co.uk | ssh-to-age' -``` - -Add a new section with this key to `.sops.yaml`: - -```yaml -creation_rules: - ... - - path_regex: hosts//secrets(/[^/]+)?\.yaml$ - key_groups: - - age: - - *barrucadu - - '' -``` - -Enable sops in the host configuration: - -```nix -sops.defaultSopsFile = ./secrets.yaml; -``` - -### Optional: Configure backups - -All hosts which run any sort of service with data I care about should take -automatic backups. - -Firstly, add the backup credentials to the secrets: - -```bash -nix run .#secrets -``` - -Then enable backups in the host configuration: - -```nix -nixfiles.backups.enable = true; -nixfiles.backups.environmentFile = config.sops.secrets."nixfiles/backups/env".path; -sops.secrets."nixfiles/backups/env" = { }; -``` - -Most services define their own backup scripts. For any other needs, write a -custom script: - -```nix -nixfiles.backups.scripts. = '' -