Workshop

Writing a NixOS Module for YOUR_APP


0xB10C

bitcoin++ 2023
no photos, ty


I'm Timo aka @0xB10C
working on Bitcoin
using Nix and NixOS

supported by a Spiral and HRF grant

Workshop Setup

  • uses free* GitHub Codespace instance
  • VSCode for editing `configuration.nix`
  • starts a NixOS VM

  • instructions on b10c.me/bpp23

Open in GitHub Codespaces

Nix vs NixOS vs NixOS module

Nix a package manager
NixOS a Linux distribution
NixOS module isolated and reusable NixOS component

NixOS Module


NixOS

Is configuration.nix a NixOS module?

Structure of a NixOS Module

              {
    imports = [
      # Paths to local modules.
      # Compose this module by combining others.
    ];

    options = {
      # Option declarations.
      # Declare what settings a user of this module can control.
      # For example, an "enable" option to let a user choose to enable it.
      # (this is an API declaration)
    };

    config = {
      # Option definitions.
      # Set options of other modules.
      # (this you using an API of another NixOS module)
    };
  }
            
          

Option declaration


  options = {

    name = mkOption {
      type = type specification;
      default = default value;
      example = example value;
      description = lib.mdDoc "Description for use in the NixOS manual.";
    };

    ...

  };
            
          

Option Types (1)

  • types.bool - A boolean, can be true or false
  • types.int - A signed integer
  • types.ints.unsigned - An unsigned integer
  • types.port - A port
  • types.str - A string
  • types.path - A filesystem path, starts with a /
  • types.package - A Nix package
  • ...

See also NixOS manual: Option Types

Option Types (2)

  • types.listOf t - A list with entries of type t
  • types.attrsOf t - An attribute set with values of type t
  • types.nullOr t - null or type t
  • ...

See also NixOS manual: Option Types

mkEnableOption

            
  lib.mkEnableOption (lib.mdDoc "magic")

  # is short for

  lib.mkOption {
    type = lib.types.bool;
    default = false;
    example = true;
    description = lib.mdDoc "Whether to enable magic.";
  }
            
          
See also NixOS manual: mkEnableOption

Example: Option declaration


  options = {
    services.bitcoind = {
      enable = mkEnableOption "Bitcoin daemon";
      ...
      dataDir = mkOption {
        type = types.path;
        default = "/var/lib/bitcoind";
        description = mdDoc "The data directory for bitcoind.";
      };
      ...
    };
  };
            
          
from nix-bitcoin/modules/bitcoind.nix

Example: Options definitions

            
  let
    cfg = config.services.bitcoind;
  in
  {
    config = mkIf cfg.enable {
      systemd.services.bitcoind = {
        after = [ "network-online.target" ];
        wantedBy = [ "multi-user.target" ];
        serviceConfig = {
          ExecStart = "${cfg.package}/bin/bitcoind -datadir='${cfg.dataDir}'";
          ...
        };
        ...
      };
    };
  }
            
          

from nix-bitcoin/modules/bitcoind.nix

Finding NixOS options

use search.nixos.org/options

Built-in Functions

  • add e1 e2 - Return the sum of e1 and e2
  • toString e - Convert the expression e to a string
  • trace e1 e2 - Print e1 and return e2. Useful for debugging.
  • map f list - Apply the function f to each element in the list list
  • ...

see Nix Reference Manual: Built-in Functions

Hands on NixOS Module writing

open b10c.me/bpp23

Workshop Setup

  • uses free* GitHub Codespace instance
  • VSCode for editing `configuration.nix`
  • starts a NixOS VM

  • instructions on b10c.me/bpp23

Open in GitHub Codespaces

your_app

mock program that

  1. connects to Bitcoin Core RPC
  2. starts a webserver


but needs RPC information and a port to listen on!

Before you start hacking

  1. wait for the VM to start
  2. use sh nixos-rebuild-vm.sh
  3. use ssh vm
  4. host$ command and vm$ command

Task 1 - First steps

  1. Enable the regtest Bitcoin Core node
  2. Using systemd tools



  1. Number of systemctl status log lines?
  2. Where is the datadir?

Task 2 - defining and declaring options

  1. Declare options for your_app_server
  2. Using the declared options
  3. Enable the your_app service in configuration.nix
  4. Open the firewall
  5. nixos-rebuild switch*

Task 3 - Security and hardening

  1. RPC password is world-readable!
    1. Where did you find it?
    2. How can this be avoided?
  2. systemd-analyze security
    1. exposure scores of bitcoind and your_app?
    2. lowest exposure score?
  3. your_app hardening

Task 4 - Containers

  1. OCI-Containers
    1. podman or docker?
  2. NixOS containers

We've covered:

  1. controlling basic systemd services
  2. nixos-rebuild*
  3. declaring and defining options
  4. sytemd hardening
  5. OCI-containers on NixOS
  6. NixOS containers

Thanks

Hackathon


github.com/0xB10C/bitcoind-gunix

A nix package of bitcoind with the goal of matching the x86_64-pc-linux-gnu GUIX release bitcoind binary.

Can we build a binary the same hash in Nix?
no photos - b10c.me/bpp23