From fe21edcc5f0a98c88ec63b4ecd9a6a7687e0572f Mon Sep 17 00:00:00 2001 From: Asko Soukka Date: Thu, 20 Feb 2025 23:20:35 +0200 Subject: [PATCH 1/5] Add doc for installing Nix package manager --- docs/nix/README.md | 7 ++ docs/nix/install.md | 151 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 docs/nix/README.md create mode 100644 docs/nix/install.md diff --git a/docs/nix/README.md b/docs/nix/README.md new file mode 100644 index 0000000..6cb15c4 --- /dev/null +++ b/docs/nix/README.md @@ -0,0 +1,7 @@ +# Nix Package Manager + +[Nix](https://nixos.org/nix/) is a package manager, which manages software and their dependencies independently from the underlying OS. With Nix, all software and their dependencies are contained in a single dedicated file system location. This makes Nix good fit when hacking M2, which ships with only minimal command line tools available by default. + +With Nix installed, you may not need to install additional packages into OS. You also may not need to use `devel-su` or `nerdctl` for most of the command-line tools or libraries you might need. + +* [Installation](install.md) diff --git a/docs/nix/install.md b/docs/nix/install.md new file mode 100644 index 0000000..d770993 --- /dev/null +++ b/docs/nix/install.md @@ -0,0 +1,151 @@ +# How to install Nix on M2 + +[Nix](https://nixos.org/nix/) has an easy to use command line install script, but it relies on availability of a few specific command line tools (`curl` and `xz`) and being able to create directory `/nix` using `sudo`. Therefore, we must take a few extra steps to get started. + + +## State directory + +At first, we must create `/nix` state directory, which will contain everything downloaded and managed by Nix. + +But we don't want to take the chance that `/nix` will ever take all free space from the system partition. That's why we create a directory under home directory + +```console +$ mkdir /home/defaultuser/Nix +``` + +and only then go to super user + +```console +$ devel-su +``` + +and bind mount the directory from home directory into `/nix`. + +```console +$ mkdir /nix +$ mount --bind /home/defaultuser/Nix /nix +``` + +At any point, all the space taken by Nix could be released (uninstalled) by just removing that state directory. + + +## Mount on boot + +While the state directory could be bind mounted manually after every boot, it is possible to configure a systemd job to do it for you. Just enter super user + +```console +$ devel-su +``` + +and create the systemd unit + +```console +$ cat << EOF > /etc/systemd/system/bind-mount-nix.service +[Unit] +Description=Bind mount /home/defaultuser/Nix to /nix +After=local-fs.target +Requires=local-fs.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/mount --bind /home/defaultuser/Nix /nix + +[Install] +WantedBy=multi-user.target +EOF +``` + +and enable it + +```console +$ systemctl daemon-reload +$ systemctl enable bind-mount-nix.service +$ systemctl start bind-mount-nix.service + +``` + + +## Bootstrap + +Next we are able to do the required bootstrapping for final installation. As a super user + +```console +$ devel-su +``` + +start a some minimal container with `/nix` mounted, install the required dependencies `curl` and `xz`, run the installer for single user "rootless" Nix installation + +```console +$ nerdctl run --rm -ti -v /nix:/nix debian:stable +$ apt-get update +$ apt-get install curl xz-utils +$ sh <(curl -L https://nixos.org/nix/install) --no-daemon +``` + +This initial installation may report some errors, but don't worry. Because it is being run in a container, it can only write into the mounted `/nix` directory. + +Once we have exited the container, we may remove the image + +```console +$ nerdctl rmi debian:stable-slim +``` + +and change the ownership of the installed files to `defaultuser`. + +```console +$ chown -R defaultuser:defaultuser /nix +``` + +Remember to exit the super user mode before continuing for the final installation + +```console +$ exit +``` + + +## Install + +Now we can finally run the installation as `defaultuser`, and going super user is no longer neededfor Nix: + +```console +$ /nix/store/*-nix-*/bin/nix shell nixpkgs#curl nixpkgs#xz --extra-experimental-features nix-command --extra-experimental-features flakes +$ sh <(curl -L https://nixos.org/nix/install) --no-daemon +``` + +It's good to know that the installation creates the following symlinks. + +``` console +/home/defaultuser/.nix-channels/ +/home/defaultuser/.nix-defexpr/ +/home/defaultuser/.nix-profile/ +``` + + +## Activate + +Installed Nix must be activated by sourcing its activation script in shell with + +```console +$ . "$HOME/.nix-profile/etc/profile.d/nix.sh" +``` + +This can be automated by creating `/home/defaultuser/.profile` (or adding to an existing file) with the activation command + +```console +$ cat << EOF > /home/defaultuser/.profile +if [ -e /nix/store ]; then + . "$HOME/.nix-profile/etc/profile.d/nix.sh" +fi +EOF +``` + +Now Nix should be activate on every new shell on M2. As a safe-guard, the actication is skipped, if the bind mount of `/nix` fails on any reason. + + +## Additional resources + +* [Nix manual on package management](https://nix.dev/manual/nix/2.24/package-management/) +* [Home Manager for more than just package management](https://nix-community.github.io/home-manager/index.xhtml#sec-install-standalone) + + From e10b1a13b9deecb37d9630a9201b8d907f70b16c Mon Sep 17 00:00:00 2001 From: Asko Soukka Date: Sat, 1 Mar 2025 00:44:02 +0200 Subject: [PATCH 2/5] Add doc about use of home-manager and Tailscaled --- docs/nix/README.md | 6 ++- docs/nix/home-manager.md | 102 +++++++++++++++++++++++++++++++++++++++ docs/nix/install.md | 87 +++++++++++++++++---------------- docs/nix/tailscale.md | 82 +++++++++++++++++++++++++++++++ 4 files changed, 231 insertions(+), 46 deletions(-) create mode 100644 docs/nix/home-manager.md create mode 100644 docs/nix/tailscale.md diff --git a/docs/nix/README.md b/docs/nix/README.md index 6cb15c4..740f72d 100644 --- a/docs/nix/README.md +++ b/docs/nix/README.md @@ -1,7 +1,9 @@ # Nix Package Manager -[Nix](https://nixos.org/nix/) is a package manager, which manages software and their dependencies independently from the underlying OS. With Nix, all software and their dependencies are contained in a single dedicated file system location. This makes Nix good fit when hacking M2, which ships with only minimal command line tools available by default. +[Nix](https://nixos.org/nix/) is a package manager that manages software and their dependencies independently from the underlying OS. With Nix, all software and their dependencies are contained in a single dedicated file system location. This makes Nix a good fit when hacking M2, which ships with only minimal command-line tools available by default. -With Nix installed, you may not need to install additional packages into OS. You also may not need to use `devel-su` or `nerdctl` for most of the command-line tools or libraries you might need. +With Nix installed, you may not need to install additional packages into the OS. You also may not need to use `devel-su` or `nerdctl` for most of the command-line tools or libraries you might need. * [Installation](install.md) +* [Home Manager](home-manager.md) +* [Tailscale](tailscale.md) diff --git a/docs/nix/home-manager.md b/docs/nix/home-manager.md new file mode 100644 index 0000000..2d8194f --- /dev/null +++ b/docs/nix/home-manager.md @@ -0,0 +1,102 @@ +# Manage your environment with Home Manager + +Home Manager is a [Nix](install.md)-powered tool for reproducible management of the contents of users’ home directories. This includes programs, configuration files, environment variables, and systemd user service management. + + +## Prerequisites + +Home Manager is a part of the Nix ecosystem. If you haven't installed Nix yet, follow the [installation guide](install.md) first. + + +## Install Home Manager + +Once you have Nix installed, you can install Home Manager by running the following commands: + +```console +nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager +nix-channel --update +nix-shell '' -A install +``` + + +## First-time activation + +After installation, you should be able to use Home Manager with: + +```console +. $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh +home-manager switch +``` + +Usually Home Manager should be activated automatically when you start a new shell, thanks to `.profile` created during the [Nix installation](install.md). + + +## First-time configuration + +Your Home Manager configuration is managed with updating `/home/defaultuser/.config/home-manager/home.nix` and running `home-manager switch` to apply the changes. + +Home Manager installs with example `home.nix` with a lot of examples. To see the forest for the trees, it might be good to put that aside and start with a minimal configuration with: + +```console +mv /home/defaultuser/.config/home-manager/home.nix /home/defaultuser/.config/home-manager/home.nix.example +``` + +and + +```console +cat << EOF > /home/defaultuser/.config/home-manager/home.nix +{ config, pkgs, lib, ... }: +{ + home.username = "defaultuser"; + home.homeDirectory = "/home/defaultuser"; + home.stateVersion = "24.11"; + home.packages = [ + pkgs.nano + ]; + programs.home-manager.enable = true; + programs.bash.enable = true; + home.file.".profile".source = lib.mkForce (builtins.toFile "profile" '' + if [ -e "$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then + . "$HOME/.nix-profile/etc/profile.d/nix.sh" + exec bash + fi + ''); +} +EOF +``` + +with `home-manager switch -b backup` to apply the changes. + +This configuration installs `nano` as a minimal editor and enables full `bash` and updates `.profile` that activates Nix on every new shell with Home Manager managed version. (The previous version of `.profile` is backed up as `.profile.backup`.) + +After this first-time configuration, you can start adding more packages and configurations to your `home.nix` and using `home-manager switch` to apply the changes. + + +## Manage Nix configuration + +Nix has a few [configuration options](https://nix.dev/manual/nix/2.24/command-ref/conf-file.html?highlight=min-free#available-settings) that can be set in `~/.config/nix/nix.conf`. Home Manager can manage these options with `nix.extraOptions` in `home.nix`. + +You should at least configure automatic garbage collection with `min-free` and `max-free` options. For example: + +```nix + nix.extraOptions = '' + min-free = 1G + max-free = 10G + ''; +``` + +Possibly, later you might want to enable experimental features like `nix-command` and `flakes` for [the next-generation Nix command-line interface](https://nix.dev/manual/nix/2.24/command-ref/experimental-commands): + +```nix + nix.extraOptions = '' + min-free = 1G + max-free = 10G + experimental-features = nix-command flakes + ''; +``` + + +## Additional resources + +* [Home Manager manual](https://nix-community.github.io/home-manager/index.xhtml) +* [All Home Manager options](https://nix-community.github.io/home-manager/options.xhtml) \ No newline at end of file diff --git a/docs/nix/install.md b/docs/nix/install.md index d770993..0471931 100644 --- a/docs/nix/install.md +++ b/docs/nix/install.md @@ -1,46 +1,46 @@ # How to install Nix on M2 -[Nix](https://nixos.org/nix/) has an easy to use command line install script, but it relies on availability of a few specific command line tools (`curl` and `xz`) and being able to create directory `/nix` using `sudo`. Therefore, we must take a few extra steps to get started. +[Nix](https://nixos.org/nix/) has an easy-to-use command line install script, but it relies on the availability of a few specific command line tools (`curl` and `xz`) and the ability to create the `/nix` directory using `sudo`. Therefore, you must take a few extra steps to get started. ## State directory -At first, we must create `/nix` state directory, which will contain everything downloaded and managed by Nix. +First, you must create the `/nix` state directory, which will contain everything downloaded and managed by Nix. -But we don't want to take the chance that `/nix` will ever take all free space from the system partition. That's why we create a directory under home directory +But you don't want to take the chance that `/nix` will ever take all free space from the system partition. That's why you create a directory under the home directory instead. ```console -$ mkdir /home/defaultuser/Nix +mkdir /home/defaultuser/Nix ``` and only then go to super user ```console -$ devel-su +devel-su ``` -and bind mount the directory from home directory into `/nix`. +and bind mount the directory from the home directory into `/nix`. ```console -$ mkdir /nix -$ mount --bind /home/defaultuser/Nix /nix +mkdir /nix +mount --bind /home/defaultuser/Nix /nix ``` -At any point, all the space taken by Nix could be released (uninstalled) by just removing that state directory. +At any point, all the space taken by Nix could be released (uninstalled) by just removing the state directory. ## Mount on boot -While the state directory could be bind mounted manually after every boot, it is possible to configure a systemd job to do it for you. Just enter super user +While the state directory could be bind mounted manually after every boot, it is possible to configure a systemd job to do it for you. Just enter super user mode: ```console -$ devel-su +devel-su ``` and create the systemd unit ```console -$ cat << EOF > /etc/systemd/system/bind-mount-nix.service +cat << EOF > /etc/systemd/system/bind-mount-nix.service [Unit] Description=Bind mount /home/defaultuser/Nix to /nix After=local-fs.target @@ -56,64 +56,65 @@ WantedBy=multi-user.target EOF ``` -and enable it +and enable it. ```console -$ systemctl daemon-reload -$ systemctl enable bind-mount-nix.service -$ systemctl start bind-mount-nix.service - +systemctl daemon-reload +systemctl enable bind-mount-nix.service +systemctl start bind-mount-nix.service ``` +Now `/nix` should be (bind) mounted on every boot. + ## Bootstrap -Next we are able to do the required bootstrapping for final installation. As a super user +Next, you are able to do the required bootstrapping for the final installation. As a super user ```console -$ devel-su +devel-su ``` -start a some minimal container with `/nix` mounted, install the required dependencies `curl` and `xz`, run the installer for single user "rootless" Nix installation +start a minimal container with `/nix` mounted, install the required dependencies `curl` and `xz`, and run the installer for a single user "rootless" Nix installation: ```console -$ nerdctl run --rm -ti -v /nix:/nix debian:stable -$ apt-get update -$ apt-get install curl xz-utils -$ sh <(curl -L https://nixos.org/nix/install) --no-daemon +nerdctl run --rm -ti -v /nix:/nix debian:stable +apt-get update +apt-get install curl xz-utils +sh <(curl -L https://nixos.org/nix/install) --no-daemon ``` -This initial installation may report some errors, but don't worry. Because it is being run in a container, it can only write into the mounted `/nix` directory. +This initial installation may report some errors, but don't worry. Since it is being run in a container, it can only write to the mounted `/nix` directory. -Once we have exited the container, we may remove the image +Once you have exited the container, you may remove the image: ```console -$ nerdctl rmi debian:stable-slim +nerdctl rmi debian:stable-slim ``` - and change the ownership of the installed files to `defaultuser`. ```console -$ chown -R defaultuser:defaultuser /nix +chown -R defaultuser:defaultuser /nix ``` -Remember to exit the super user mode before continuing for the final installation +Remember to exit the super user mode before continuing with the final installation. The rest of the installation should be done as `defaultuser`. + ```console -$ exit +exit ``` ## Install -Now we can finally run the installation as `defaultuser`, and going super user is no longer neededfor Nix: +Now you can finally run the installation as `defaultuser`, and going super user is no longer needed for Nix: ```console -$ /nix/store/*-nix-*/bin/nix shell nixpkgs#curl nixpkgs#xz --extra-experimental-features nix-command --extra-experimental-features flakes -$ sh <(curl -L https://nixos.org/nix/install) --no-daemon +/nix/store/*-nix-*/bin/nix shell nixpkgs#curl nixpkgs#xz --extra-experimental-features nix-command --extra-experimental-features flakes +sh <(curl -L https://nixos.org/nix/install) --no-daemon ``` -It's good to know that the installation creates the following symlinks. +It's good to know that the installation creates the following symlinks: ``` console /home/defaultuser/.nix-channels/ @@ -124,28 +125,26 @@ It's good to know that the installation creates the following symlinks. ## Activate -Installed Nix must be activated by sourcing its activation script in shell with +Installed Nix must be activated by sourcing its activation script in the shell with ```console -$ . "$HOME/.nix-profile/etc/profile.d/nix.sh" +. "$HOME/.nix-profile/etc/profile.d/nix.sh" ``` -This can be automated by creating `/home/defaultuser/.profile` (or adding to an existing file) with the activation command +This can be automated by creating `/home/defaultuser/.profile` (or adding to an existing file) with the activation command: ```console -$ cat << EOF > /home/defaultuser/.profile -if [ -e /nix/store ]; then +cat << EOF > /home/defaultuser/.profile +if [ -e "$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then . "$HOME/.nix-profile/etc/profile.d/nix.sh" fi EOF ``` -Now Nix should be activate on every new shell on M2. As a safe-guard, the actication is skipped, if the bind mount of `/nix` fails on any reason. +Now Nix should be activated on every new shell on M2. As a safeguard, the activation is skipped if the bind mount of `/nix` fails for any reason. ## Additional resources * [Nix manual on package management](https://nix.dev/manual/nix/2.24/package-management/) -* [Home Manager for more than just package management](https://nix-community.github.io/home-manager/index.xhtml#sec-install-standalone) - - +* [Home Manager for more than just package management](https://nix-community.github.io/home-manager/index.xhtml#sec-install-standalone) \ No newline at end of file diff --git a/docs/nix/tailscale.md b/docs/nix/tailscale.md new file mode 100644 index 0000000..41d6e46 --- /dev/null +++ b/docs/nix/tailscale.md @@ -0,0 +1,82 @@ +# Activating Tailscale + +[Tailscale](https://tailscale.com/) is a VPN service that allows you to connect to your devices securely. It is a good fit for M2, which is a headless device that you may want to access remotely, and also works when run in user space (as `defaultuser`). + + +## Prerequisites + +Before you start, you need to have Nix installed and Home Manager activated. If you haven't installed Nix yet, follow the [installation guide](install.md) first and activate Home Manager as described in the [Home Manager guide](home-manager.md). + + +## Register machine + +To use Tailscale, you need to register your machine for your Tailnet. + +Because `tailscale` command does not support custom socket path, the registration must be done with the default socket path. + +This means that you enter super user mode + +```console +devel-su +``` + +and create the default socket path before continuing with the registration. + +```console +mkdir -p /var/run/tailscale +chown defaultuser:defaultuser /var/run/tailscale/ +``` + +Then you can return to `defaultuser` mode. + +```console +exit +``` + +Now you may manually start the tailscale daemon with user space networking, but with the default socket path + +```console +nix-shell -p tailscale --run "tailscaled --tun=userspace-networking" +``` + +and then run the registration in another shell + +```console +nix-shell -p tailscale --run "tailscale up" +``` + +and follow the instructions. + +This should already bring your M2 into your Tailnet, until you break the daemon with `Ctrl+C`. + + +## Register service + +To make sure that Tailscale starts automatically when you start your M2, you can create a systemd user service for it in your `home.nix` configuration: + +```nix + systemd.user.services.tailscaled = { + Unit = { + Description = "Tailscale client daemon"; + After = [ "network.target" ]; + }; + Service = { + ExecStart = "${pkgs.tailscale}/bin/tailscaled --tun=userspace-networking --socket ${config.home.homeDirectory}/.local/share/tailscale/tailscaled.sock"; + Restart = "always"; + RestartSec = 5; + }; + Install = { + WantedBy = [ "default.target" ] ; + }; + }; + + # Ensure home-manager activates the systemd service + home.activation.activateSystemd = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + /usr/bin/systemctl --user daemon-reload + /usr/bin/systemctl --user enable tailscaled --now + ''; +``` + +When ready, run `home-manager switch` to apply the changes. + +This will start the Tailscale daemon with user space networking and the custom socket path when you start your M2. From e5161c7aea1de7fb3680b8762ede9fd39fc762d1 Mon Sep 17 00:00:00 2001 From: Asko Soukka Date: Mon, 3 Mar 2025 22:11:23 +0200 Subject: [PATCH 3/5] Fix to use `debian:stable-slim` in the Nix bootstrap --- docs/nix/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/nix/install.md b/docs/nix/install.md index 0471931..8894453 100644 --- a/docs/nix/install.md +++ b/docs/nix/install.md @@ -78,7 +78,7 @@ devel-su start a minimal container with `/nix` mounted, install the required dependencies `curl` and `xz`, and run the installer for a single user "rootless" Nix installation: ```console -nerdctl run --rm -ti -v /nix:/nix debian:stable +nerdctl run --rm -ti -v /nix:/nix debian:stable-slim apt-get update apt-get install curl xz-utils sh <(curl -L https://nixos.org/nix/install) --no-daemon From 1fa60f92e574df4accdacaf1f247e5dcf1c981f9 Mon Sep 17 00:00:00 2001 From: Asko Soukka Date: Tue, 4 Mar 2025 19:13:48 +0200 Subject: [PATCH 4/5] Update systemd service instructions for tailscaled --- docs/nix/tailscale.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/docs/nix/tailscale.md b/docs/nix/tailscale.md index 41d6e46..a4ddec4 100644 --- a/docs/nix/tailscale.md +++ b/docs/nix/tailscale.md @@ -69,14 +69,9 @@ To make sure that Tailscale starts automatically when you start your M2, you can WantedBy = [ "default.target" ] ; }; }; - - # Ensure home-manager activates the systemd service - home.activation.activateSystemd = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - /usr/bin/systemctl --user daemon-reload - /usr/bin/systemctl --user enable tailscaled --now - ''; + systemd.user.startServices = true; ``` -When ready, run `home-manager switch` to apply the changes. +When ready, run `home-manager switch` to apply the changes and `systemctl --user start tailscaled` to start the service for the first time. Later it will be automatically started e.g. after a system reboot. This will start the Tailscale daemon with user space networking and the custom socket path when you start your M2. From 04ce15b97371e1d8047b0bdda2a8fab7dbfc2799 Mon Sep 17 00:00:00 2001 From: Asko Soukka Date: Tue, 4 Mar 2025 19:16:32 +0200 Subject: [PATCH 5/5] Add to configure `nix.package` with `nix.extraOptions` --- docs/nix/home-manager.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/nix/home-manager.md b/docs/nix/home-manager.md index 2d8194f..95d111d 100644 --- a/docs/nix/home-manager.md +++ b/docs/nix/home-manager.md @@ -79,6 +79,7 @@ Nix has a few [configuration options](https://nix.dev/manual/nix/2.24/command-re You should at least configure automatic garbage collection with `min-free` and `max-free` options. For example: ```nix + nix.package = pkgs.nix; nix.extraOptions = '' min-free = 1G max-free = 10G @@ -88,6 +89,7 @@ You should at least configure automatic garbage collection with `min-free` and ` Possibly, later you might want to enable experimental features like `nix-command` and `flakes` for [the next-generation Nix command-line interface](https://nix.dev/manual/nix/2.24/command-ref/experimental-commands): ```nix + nix.package = pkgs.nix; nix.extraOptions = '' min-free = 1G max-free = 10G @@ -99,4 +101,4 @@ Possibly, later you might want to enable experimental features like `nix-command ## Additional resources * [Home Manager manual](https://nix-community.github.io/home-manager/index.xhtml) -* [All Home Manager options](https://nix-community.github.io/home-manager/options.xhtml) \ No newline at end of file +* [All Home Manager options](https://nix-community.github.io/home-manager/options.xhtml)