Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/nix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Nix Package Manager

[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 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)
104 changes: 104 additions & 0 deletions docs/nix/home-manager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# 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 '<home-manager>' -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.package = pkgs.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.package = pkgs.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)
150 changes: 150 additions & 0 deletions docs/nix/install.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# How to install Nix on M2

[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

First, you must create the `/nix` state directory, which will contain everything downloaded and managed by Nix.

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
```

and only then go to super user

```console
devel-su
```

and bind mount the directory from the 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 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 mode:

```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
```

Now `/nix` should be (bind) mounted on every boot.


## Bootstrap

Next, you are able to do the required bootstrapping for the final installation. As a super user

```console
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-slim
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. Since it is being run in a container, it can only write to the mounted `/nix` directory.

Once you have exited the container, you 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 with the final installation. The rest of the installation should be done as `defaultuser`.


```console
exit
```


## Install

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
```

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 the 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 "$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
fi
EOF
```

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)
77 changes: 77 additions & 0 deletions docs/nix/tailscale.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 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" ] ;
};
};
systemd.user.startServices = true;
```

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.