About me: My name is Solène Rapenne. I like learning and sharing my knowledge related to IT stuff. Hobbies: '(BSD OpenBSD h+ Lisp cmdline gaming internet-stuff). I love percent and lambda characters. OpenBSD developer solene@.

Contact me: solene on Freenode, solene+www at dataswamp dot org or solene@bsd.network (mastodon). If for some reason you want to give me some money, I accept paypal at the address donate@perso.pw.

Making a home NAS using NixOS

Written by Solène, on 18 October 2020.
Tags: #nixos #linux #nas

Comments on Mastodon

Still playing with NixOS, I wanted to experience how difficult it would be to write a NixOS configuration file to turn a computer into a simple NAS with basics features: samba storage, dlna server and auto suspend/resume.

What is NixOS? As a reminder for some and introduction to the others, NixOS is a Linux distribution built by the Nix package manager, which make it very different than any other operating system out there, except Guix which has a similar approach with their own package manager written in Scheme.

NixOS uses a declarative configuration approach along with lot of others features derived from Nix. What’s big here is you no longer tweak anything in /etc or install packages, you can define the working state of the system in one configuration file. This system is a totally different beast than the others OS and require some time to understand how it work. Good news though, everything is documented in the man page configuration.nix, from fstab configuration to users managements or how to enable samba!

Here is the /etc/nixos/configuration.nix file on my NAS.

It enables ssh server, samba, minidlna and vnstat. Set up an user with my ssh public key. Ready to work.

Using rtcwake command (Linux specific), it’s possible to put the system into standby mode and schedule an auto resume after some time. This is triggered by a cron job at 01h00.

{ config, pkgs, ... }:
{
  # include stuff related to hardware, auto generated at install
  imports = ./hardware-configuration.nix ];
  boot.loader.grub.device = "/dev/sda";

  # network configuration
  networking.interfaces.enp3s0.ipv4.addresses = [ {
    address = "192.168.42.150";
    prefixLength = 24;
  } ];
  networking.defaultGateway = "192.168.42.1";
  networking.nameservers = [ "192.168.42.231" ];

  # FR locales and layout
  i18n.defaultLocale = "fr_FR.UTF-8";
  console = { font = "Lat2-Terminus16"; keyMap = "fr"; };
  time.timeZone = "Europe/Paris";

  # Packages management
  environment.systemPackages = with pkgs; [
    kakoune vnstat borgbackup utillinux
  ];

  # network disabled (I need to check the ports used first)
  networking.firewall.enable = false;

  # services to enable
  services.openssh.enable = true;
  services.vnstat.enable = true;

  # auto standby
  services.cron.systemCronJobs = [
      "0 1 * * * root rtcwake -m mem --date +6h"
  ]; 

  # samba service
  services.samba.enable = true;
  services.samba.enableNmbd = true;
  services.samba.extraConfig = ''
        workgroup = WORKGROUP
        server string = Samba Server
        server role = standalone server
        log file = /var/log/samba/smbd.%m
        max log size = 50
        dns proxy = no
        map to guest = Bad User
    '';
  services.samba.shares = {
      public = {
          path = "/home/public";
          browseable = "yes";
          "writable" = "yes";
          "guest ok" = "yes";
          "public" = "yes";
          "force user" = "share";
        };
     };

  # minidlna service
  services.minidlna.enable = true;
  services.minidlna.announceInterval = 60;
  services.minidlna.friendlyName = "Rorqual";
  services.minidlna.mediaDirs = ["A,/home/public/Musique/" "V,/home/public/Videos/"];

  # trick to create a directory with proper ownership
  # note that tmpfiles are not necesserarly temporary if you don't
  # set an expire time. Trick given on irc by someone I forgot the name..
  systemd.tmpfiles.rules = [ "d /home/public 0755 share users" ];

  # create my user, with sudo right and my public ssh key
  users.users.solene = {
    isNormalUser = true;
    extraGroups = [ "wheel" "sudo" ];
    openssh.authorizedKeys.keys = [
          "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOIZKLFQXVM15viQXHYRjGqE4LLfvETMkjjgSz0mzMzS personal"
          "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOIZKLFQXVM15vAQXBYRjGqE6L1fvETMkjjgSz0mxMzS pro"
    ];
  };

  # create a dedicated user for the shares
  # I prefer a dedicated one than "nobody"
  # can't log into it
  users.users.share= {
    isNormalUser = false;
  };
}

NixOS optional features in packages

Written by Solène, on 14 October 2020.
Tags: #nixos #linux

Comments on Mastodon

As a claws-mail user, I like to have calendar support in the mail client to be able to “accept” invitations. In the default NixOS claws-mail package, the vcalendar module isn’t installed with the package. Still, it is possible to add support for the vcalendar module without ugly hack.

It turns out, by default, the claws-mail package in Nixpkg has an optional build option for the vcalendar module, we need to tell nixpkg we want this module and claws-mail will be compiled.

As stated in the NixOS manual, the optionals features can’t be searched yet. So what’s possible is to search for your package in the NixOS packages search, click on the package name to get to the details and click on the link named “Nix expression” that will open a link to the package definition on GitHUB, claws-mail nix expression

As you can see on the claws-mail nix expression code, there are lot of lines with optional, those are features we can enable. Here is a sample:

[..]
++ optional (!enablePluginArchive) "--disable-archive-plugin"
++ optional (!enablePluginLitehtmlViewer) "--disable-litehtml_viewer-plugin"
++ optional (!enablePluginPdf) "--disable-pdf_viewer-plugin"
++ optional (!enablePluginPython) "--disable-python-plugin"
[..]

In your configuration.nix file, where you define the package list you want, you can tell you want to enable the plugin vcalendar, this is done as in the following example:

environment.systemPackages = with pkgs; [
  kakoune git firefox irssi minetest
  (pkgs.claws-mail.override { enablePluginVcalendar = true;})
];

When you rebuild your system to match the configuration definition, claws-mail will be compiled with the extras options you defined.

Now, I have claws-mail with vCalendar support.

Unlock a full disk encryption NixOS with usb memory stick

Written by Solène, on 06 October 2020.
Tags: #nixos #linux

Comments on Mastodon

Using NixOS on a laptop on which the keyboard isn’t detected when I need to type the password to decrypt disk, I had to find a solution. This problem is hardware related, not Linux or NixOS related.

I highly recommend using full disk encryption on every computer following a thief threat model. Having your computer stolen is bad, but if the thief has access to all your data, you will certainly be in trouble.

This was time to find how to use an usb memory stick to unlock the full disk encryption in case I don’t have my hands on an usb keyboard to unlock the computer.

There are 4 steps to enable unlocking the luks volume using a device.

  1. Create the key
  2. Add the key on the luks volume
  3. Write the key on the usb device
  4. Configure NixOS

First step, creating the file. The easiest way is to the following:

# dd if=/dev/urandom of=/root/key.bin bs=4096 count=1

This will create a 4096 bytes key. You can choose the size you want.

Second step is to register that key in the luks volume, you will be prompted for luks password when doing so.

# cryptsetup luksAddKey /dev/sda1 /root/key.bin

Then, it’s time to write the key to your usb device, I assume it will be /dev/sdb.

# dd if=/root/key.bin of=/dev/sdb bs=4096 count=1

And finally, you will need to configure NixOS to give the information about the key. It’s important to give the correct size of the key. Don’t forget to adapt "crypted" to your luks volume name.

boot.initrd.luks.devices."crypted".keyFileSize = 4096;
boot.initrd.luks.devices."crypted".keyFile = "/dev/sdb";

Rebuild your system with nixos-rebuild switch and voilà!

Going further

I recommend using the fallback to password feature so if you lose or don’t have your memory stick, you can type the password to unlock the disk. Note that you need to not put anything looking like a /dev/sdb because if it exists and no key are there, the system won’t ask for password, and you will need to reboot.

boot.initrd.luks.devices."crypted".fallbackToPassword = true;

It’s also possible to write the key in a partition or at a specific offset into your memory disk. For this, look at boot.initrd.luks.devices."volume".keyFileOffset entry.