7 Days0Site 7 Days0
30 Days0Site 30 Days0
Total0Site Total0

NixOS Configurations | NixOS 不完全手记

Date: 2023/06/05
Last Updated: 2023-11-03T23:59:11.000Z
Categories: NixOS
Tags: Linux, NixOS, Nix, System, OpenSource
Read Time: 2 minutes

0.1 Contents

0.2 Intro

Some note for NixOS configurations.

0.3 Useful Commands

0.3.1 Rebuild the System

Need sudo.

# test the configuration
sudo nixos-rebuild test --flake "/path/to/config#tag" --show-trace

# switch to the configuration
sudo nixos-rebuild switch --flake "/path/to/config#tag" --show-trace

0.4 Useful Websites

NixOS Full Options List

NixOS Package List

GitHub User Public Key

0.5 Put File Under /etc

Check

{
    example-configuration-file =
    { 
        source = "./file.conf.example";
        mode = "0440";
    };
    "default/useradd".text = "GROUP=100 ...";
}

0.6 Reference Store Path of a Nix Package

''
${pkgs.hello}/bin/hello
''

0.7 Use Agenix to Manage Secrets

Check agenix GitHub.

0.7.1 Install Agenix Via Flakes

{
  inputs.agenix.url = "github:ryantm/agenix";
  # optional, not necessary for the module
  #inputs.agenix.inputs.nixpkgs.follows = "nixpkgs";
  # optionally choose not to download darwin deps (saves some resources on Linux)
  #inputs.agenix.inputs.darwin.follows = "";

  outputs = { self, nixpkgs, agenix }: {
    # change `yourhostname` to your actual hostname
    nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
      # change to your system:
      system = "x86_64-linux";
      modules = [
        ./configuration.nix
        agenix.nixosModules.default
      ];
    };
  };
}

0.7.2 Get Secrets

agenix use ssh keys as keys.

System host ssh key is at /etc/ssh/.

User's ssh key is at ~/.ssh.

0.7.3 Mkdir For Agenix

mkdir -p ./secrets

0.7.4 Add Secrets Keys

Keys should be put at ./secrets/secrets.nix.

# ./secrets/secrets.nix
let
  user1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0idNvgGiucWgup/mP78zyC23uFjYq0evcWdjGQUaBH";
  user2 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILI6jSq53F/3hEmSs+oq9L4TwOo1PrDMAgcA1uo1CCV/";
  users = [ user1 user2 ];

  system1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJDyIr/FSz1cJdcoW69R+NrWzwGK/+3gJpqD1t8L2zE";
  system2 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKzxQgondgEYcLpcPdJLrTdNgZ2gznOHCAxMdaceTUT1";
  systems = [ system1 system2 ];
in
{
  "secret1.age".publicKeys = [ user1 system1 ];
  "secret2.age".publicKeys = users ++ systems;
}

This file declare that the secret1.age can be decrypted by user1 and system1. secret2.age can be decrypted by all users in users and systems.

0.7.5 Add Secrets

# You need to be in the same directory as secrets.nix
cd ./secrets

# This will open your editor ($EDITOR) to create the secret
agenix -e secret1.age

0.7.6 Add Secrets to NixOS Configurations

{
  # this will allow you to use the secrets in your NixOS configuration as a string
  age.secrets.secret1.file = ../secrets/secret1.age;
}

Or,

{
  # this will allow you to access the at the path /etc/secret1 with the correct permissions
  age.secrets.secret1 = {
    file = ../secrets/secret1
    path = "/etc/secret1";;
    mode = "770";
    owner = "nginx";
    group = "nginx";
  };
}

0.7.7 Use Secrets

0.7.7.1 Use Path of Secrets

{
  users.users.user1 = {
    isNormalUser = true;
    passwordFile = config.age.secrets.secret1.path;
  };
}

0.7.7.2 Replace Inplace Strings With Secrets

Considering that there still might be some modules which doesn't support reading secrets from a file, you could provide a placeholder string instead of a clear-text password and replace this placeholder with the secret provided by Agenix.

In the following example, the Dex module creates the config file /run/dex/config.yaml containing the placeholder string @dex-user-password@. The activation script will read the Agenix secret from config.age.secret.dex-user-password.path and replace the placeholder string with the actual secret.

system.activationScripts."dex-user-secret" = ''
  secret=$(cat "${config.age.secrets.dex-user-password.path}")
  configFile=/run/dex/config.yaml
  ${pkgs.gnused}/bin/sed -i "s#@dex-user-password@#$secret#" "$configFile"
'';

0.8 Mount WebDav Using AutoFS

I found this two links really helpful.

https://askubuntu.com/questions/821123/autofs-and-webdav-how-to-make-them-work-together

https://www.reddit.com/r/NixOS/comments/b5p6f7/how_do_i_use_davfs2/

First you need to install agenix as a way to manage your WebDav secrets.

Then you need to add the following to your configuration.nix. This will mount your WebDav to /mnt/{{ mount-dir }}.

{
  age.secrets = {
    webdav-secrets = {
      file = ./secrets/{{ your secret file }};
      owner = "root";
      group = "root";
      mode = "600";
      # this is the path where the secret will be mounted
      path = "/etc/davfs2/secrets";
    };
  };

  # put the configuration for davfs2 in the /etc/davfs2 directory
  environment.etc."davfs2/auto.mount" = {
    # rw means read-write, ro means read-only
    # you need to add backslash `\` before ':' and '#' in your url
    text = ''
      {{ mount-dir }} -fstype=davfs,conf=/etc/davfs2/conf,rw {{ your webdav url }}
    '';
    mode = "0440";
  };
  environment.etc."davfs2/conf" = {
    text = ''
      secrets /etc/davfs2/secrets
    '';
    mode = "0440";
  };

  # enable the service
  services.davfs2.enable = true;
  services.autofs = {
    enable = true;
    autoMaster = "/mnt/ /etc/davfs2/auto.mount";
  };
}

0.9 Clean the System & Nix Store

# clean journalctl
services.cron = {
  enable = true;
  systemCronJobs = [
    "0 0 * * * journalctl --vacuum-time=7d 1>/dev/null"
  ];
};

# garbange collection check https://nixos.wiki/wiki/Nix_Cookbook#Reclaim_space_on_Nix_install.3F
nix.gc.automatic = true;
nix.settings.auto-optimise-store = true;

0.10 Enable the Mosh Server

# Enable mosh, the ssh alternative when client has bad connection
# Opens UDP ports 60000 ... 61000
programs.mosh.enable = true;
networking.firewall.allowedTCPPortRanges = [
  {
    from = 60000;
    to = 61000;
  }
];
networking.firewall.allowedUDPPortRanges = [
  {
    from = 60000;
    to = 61000;
  }
];

0.11 Enable Fail2Ban

services.fail2ban = {
  enable = true;
  maxretry = 5;
  ignoreIP = [
    "127.0.0.0/8" 
    "10.0.0.0/8" 
    "172.16.0.0/12" 
    "192.168.0.0/16"
    "8.8.8.8"
  ];
};