NixOS configuration facilities for CCC Bremen infrastructure
Find a file
2025-11-28 20:02:21 +01:00
config config/mail-accounts: additional mail aliases 2025-09-08 00:20:58 +02:00
hosts hosts/devault(keycloak): use production keycloak hostname 2025-11-28 20:02:21 +01:00
lib lib/mail: no vmailbox entries for forwardings 2025-09-06 20:55:59 +02:00
modules modules/mailman: always restart mailman-listsetup.service 2025-11-28 19:08:39 +01:00
pkgs pkgs: remove unused with pkgs 2025-09-25 00:44:08 +02:00
default.nix top-level: introduce a simple nixpkgs overlay 2025-09-20 19:59:10 +02:00
README.md Fix bullet points in README, now really 2025-09-06 21:16:55 +02:00

NixOS configuration facilities for CCC Bremen infrastructure

Structure

The top-level directories modules, hosts, and config differentiate between three types, namely NixOS modules, host modules, and configuration modules, respectively.

A NixOS module is an ordinary module used for parametrizable configuration tasks much like upstream NixOS modules. The only difference is that the NixOS modules provided in this repository are namespaced under ccchb, i.e. options are located under the ccchb hierarchy. For instance, the option ccchb.common.enable enables the NixOS module ccchb.common, which is located in modules/common.nix.

A host module declares the system configuration of a single host, up to hardware-dependent settings usually defined in the local hardware-configuration.nix. Instructive examples are hosts/mail.nix and hosts/doord-pi-1.nix. In order to build, for example, an image for the host doord-pi-1.nix, one may use

nixos-rebuild build-image -I nixos-config=./hosts/doord-pi-1.nix \
    --image-variant sd-card

The more common alternative is to checkout this repository to a host, which is configured by a host module, and import the host module in /etc/nixos/configuration.nix:

{ config, lib, pkgs, ... }: {
    imports = [
        ./hardware-configuration.nix
        ./nixos-configuration/hosts/mail.nix
    ];
}

Lastly, a configuration module contains commonly used configuration options. See below in the section Configuration modules for more details.

Workflow

This repository contains custom NixOS modules, which describe concrete hosts. As these hosts are actual deployments and these are stateful in their nature, the challenge is to track this state as faithful as possible in the version control (i.e. this Git repository).

The main branch tracks the latest modifications of the modules. It is where changes are to be committed and/or merged, depending on the details of the workflow. Furthermore, the main branch is the basis for new deployments: Specification of new deployments happens first in the main branch. Then, new deployments are deployed from the main branch.

The state of every deployment is tracked by an individual branch with the prefix deploy/, which is called the deployment branch of a deployment. This branch is supposed to reflect the actual state of the deployment. Moreover, the deployment branch of a deployment is the checkout branch for the copy of this repository on that deployment.

The user may choose two tactics when updating a deployment branch on modification of a deployment:

  • They can decide to commit the changes to main, and then merge/rebase the main branch into the deployment branch. Then, they fetch the updated deployment branch on the checkout on the deployment, and perform the necessary steps to deploy the changes. If this fails, the deployment branch is ahead of the state of the actual deployment.
  • They can commit the changes to main, checkout the main branch on the deployment, and perform the steps to deploy the changes. Then, after doing the deployment, they reset the deployment branch to the main branch. This guarantees that the deployment branch always reflects the state of the actual deployment, given the user does not forget to reset the deployment branch after deploying.

Configuration modules

Users

Users may be declared globally in the config/users.nix module, and instantiated on a per-host basis by setting users.users accordingly. For example,

{ local, ... }: { {
    users.users = local.lib.callUsers {
        inherit (local.config.users) fritz genofire crest humm;
    } { };
}

instantiates the users fritz, genofire, crest, and humm.

Technically, a user under local.config.users is a module, which can be instantiated by the local.lib.callUser library function. Each user module currently receives the following, well-known arguments:

  • adminGroups: A list of common admin groups for NixOS
  • desktopGroups: A list of common desktop groups for NixOS

Mail accounts and forwardings

Mail accounts and forwardings are declared globally in the config/mail-accounts.nix module. Each mail account is represented by an attribute set, with the following keys:

  • forwardTo (optional): Email address for forwarding
  • hashedPassword (optional): Password hash for Dovecot
  • aliases (optional): List of email addresses that alias the declared account

Mail accounts can be transformed by using the local.lib.callMailAccount library function to a attribute set consisting of a passwd line for Dovecot, a vmailbox line for virtual_mailbox_maps in Postfix, and virtual lines for virtual_alias_maps in Postfix. The library function callMailAccount receives the canonical mail address for the account as its first argument, and the attribute set describing the mail account as its second argument. For example,

local.lib.callMailAccount "test@ccchb.de" {
    aliases = [
        "test2@ccchb.de"
    ];
    forwardTo = "test3@ccchb.de";
    hashedPassword = "...";
}

creates the required map entries for the mail account "test@ccchb.de", which has the alias "test2@ccchb.de", forwards mail to "test3@ccchb.de", and has a hashedPassword declared for authentication purposes (e.g. SMTP and IMAP).