NixOS / nix

Nix, the purely functional package manager
https://nixos.org/
GNU Lesser General Public License v2.1
12.24k stars 1.48k forks source link

Installation took some hacking on Synology (x86_64): /bin/sh is "weird", /tmp is noexec and / is tiny #10324

Open pmorch opened 6 months ago

pmorch commented 6 months ago

Describe the bug

Steps To Reproduce

/bin/sh on Synology is weird, apparently

Trying to run:

$ sh <(curl -L https://nixos.org/nix/install) --no-daemon
-sh: syntax error near unexpected token `('

So instead I downloaded and ran the script the old fashioned way.

/tmp mounted noexec

$ curl -L -o pmorch-nix-install https://nixos.org/nix/install
$ sh pmorch-nix-install 
downloading Nix 2.21.0 binary tarball for x86_64-linux from 'https://releases.nixos.org/nix/nix-2.21.0/nix-2.21.0-x86_64-linux.tar.xz' to '/tmp/nix-binary-tarball-unpack.GKJ6ZE1D9e'...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 21.8M  100 21.8M    0     0  40.1M      0 --:--:-- --:--:-- --:--:-- 40.2M
Running tar -xJf /tmp/nix-binary-tarball-unpack.GKJ6ZE1D9e/nix-2.21.0-x86_64-linux.tar.xz -C /tmp/nix-binary-tarball-unpack.GKJ6ZE1D9e/unpack
Running /tmp/nix-binary-tarball-unpack.GKJ6ZE1D9e/unpack/nix-2.21.0-x86_64-linux/install
orig-pmorch-nix-install: line 119: /tmp/nix-binary-tarball-unpack.GKJ6ZE1D9e/unpack/nix-2.21.0-x86_64-linux/install: Permission denied

Permission denied is because /tmp on a synology is mounted noexec:

$ mount | grep /tmp
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec)

So I created /var/services/homes/peteradmin/nixtmpdir and modified the script:

--- orig-pmorch-nix-install 2024-03-26 00:51:20.753054444 +0100
+++ pmorch-nix-install  2024-03-26 00:52:30.411060397 +0100
@@ -12,12 +12,7 @@

 umask 0022

-tmpDir="$(mktemp -d -t nix-binary-tarball-unpack.XXXXXXXXXX || \
-          oops "Can't create temporary directory for downloading the Nix binary tarball")"
-cleanup() {
-    rm -rf "$tmpDir"
-}
-trap cleanup EXIT INT QUIT TERM
+tmpDir=/var/services/homes/peteradmin/nixtmpdir

 require_util() {
     command -v "$1" > /dev/null 2>&1 ||

Partition / runs full

And now "No space left on device":

$ sh pmorch-nix-install 
downloading Nix 2.21.0 binary tarball for x86_64-linux from 'https://releases.nixos.org/nix/nix-2.21.0/nix-2.21.0-x86_64-linux.tar.xz' to '/var/services/homes/peteradmin/nixtmpdir'...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 21.8M  100 21.8M    0     0  75.7M      0 --:--:-- --:--:-- --:--:-- 75.9M
Running tar -xJf /var/services/homes/peteradmin/nixtmpdir/nix-2.21.0-x86_64-linux.tar.xz -C /var/services/homes/peteradmin/nixtmpdir/unpack
Running /var/services/homes/peteradmin/nixtmpdir/unpack/nix-2.21.0-x86_64-linux/install
Note: a multi-user installation is possible. See https://nixos.org/manual/nix/stable/installation/installing-binary.html#multi-user-installation
performing a single-user installation of Nix...
directory /nix does not exist; creating it by running 'mkdir -m 0755 /nix && chown peteradmin /nix' using sudo
copying Nix to /nix/store....................................................
installing 'nix-2.21.0'
building '/nix/store/dfag5n95d0cs8wc5i7va87gvpzcd33sj-user-environment.drv'...
unpacking 1 channels...
error: failed to extract archive (Write failed)
error: writing to file: No space left on device
error: program '/nix/store/n4qf06iv9qhn6sj1nqpzxh0yxyddmxax-nix-2.21.0/bin/nix-env' failed with exit code 1
Fetching the nixpkgs channel failed. (Are you offline?)
To try again later, run "nix-channel --update nixpkgs".

Installation finished!  To ensure that the necessary environment
variables are set, please add the line

  . 

to your shell profile (e.g. ~/.profile).

And yes, partition / is tiny.

Workaround:

$ sudo rm -rf /nix
$ sudo mkdir /volume1/nix
$ sudo chown $USER: /volume1/nix
$ sudo chmod go+rx /volume1/nix
$ ls -ld /volume1/nix
drwxr-xr-x 1 peteradmin users 0 Mar 26 01:16 /volume1/nix
$ sudo mkdir /nix
$ sudo mount -o bind /volume1/nix /nix

Installation (mostly) works now

$ sh pmorch-nix-install 
downloading Nix 2.21.0 binary tarball for x86_64-linux from 'https://releases.nixos.org/nix/nix-2.21.0/nix-2.21.0-x86_64-linux.tar.xz' to '/var/services/homes/peteradmin/nixtmpdir'...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 21.8M  100 21.8M    0     0  74.6M      0 --:--:-- --:--:-- --:--:-- 74.9M
Running tar -xJf /var/services/homes/peteradmin/nixtmpdir/nix-2.21.0-x86_64-linux.tar.xz -C /var/services/homes/peteradmin/nixtmpdir/unpack
Running /var/services/homes/peteradmin/nixtmpdir/unpack/nix-2.21.0-x86_64-linux/install
Note: a multi-user installation is possible. See https://nixos.org/manual/nix/stable/installation/installing-binary.html#multi-user-installation
performing a single-user installation of Nix...
copying Nix to /nix/store....................................................
installing 'nix-2.21.0'
building '/nix/store/dfag5n95d0cs8wc5i7va87gvpzcd33sj-user-environment.drv'...
unpacking 1 channels...

Installation finished!  To ensure that the necessary environment
variables are set, please add the line

  . 

to your shell profile (e.g. ~/.profile).

I'm not sure what line I should add to my ~/.profile, but I assume it is:

export PATH=$PATH:~/.nix-profile/bin

Test

$ nix-shell -p hello --run hello
bla bla bla
Hello, world!
pmorch commented 6 months ago

I also think there is something fishy with the locale setup on a Synology.

This fixes it (and I put it in my ~/.bashrc):

$ export LOCALE_ARCHIVE="$(nix-env --installed --no-name --out-path --query glibc-locales)/lib/locale/locale-archive"
# before
$ nix-shell -p hello --run hello
bash: warning: setlocale: LC_ALL: cannot change locale (en_US.utf8)
Hello, world!

$ export LOCALE_ARCHIVE="$(nix-env --installed --no-name --out-path --query glibc-locales)/lib/locale/locale-archive"

# after
$ nix-shell -p hello --run hello
Hello, world!

And don't fall for Locales - NixOS Wiki's suggestion of export LOCALE_ARCHIVE=/usr/lib/locale/locale-archive - that file from Synology is not up to the task.

pmorch commented 5 months ago

I just tried to install multi-user Nix on a test Synology installation using vdsm/virtual-dsm: Virtual DSM in a Docker container, and it seems it would be an uphill battle getting multi-user Nix to work:

$ sh pmorch-nix-install --daemon
<snip>
~~> Setting up the build group nixbld

---- sudo execution ------------------------------------------------------------
I am executing:

    $ sudo groupadd -g 30000 --system nixbld

Create the Nix build group, nixbld

sudo: groupadd: command not found

---- oh no! --------------------------------------------------------------------
Oh no, something went wrong. If you can take all the output and open
an issue, we'd love to fix the problem so nobody else has this issue.

:(

We'd love to help if you need it.

You can open an issue at
https://github.com/NixOS/nix/issues/new?labels=installer&template=installer.md

Or get in touch with the community: https://nixos.org/community

And yes, Synology DSM does not provide groupadd or useradd. Go figure.

pmorch commented 5 months ago

Feel free to close this issue. I just wanted to document this for the next poor bastard that wants to try it. If there is a better place for me to put this, let me know.

tastycode commented 2 months ago

@pmorch You are a personal saint to me, if i should ever give birth to progeny. I will give them your name as one of their middle names.

tastycode commented 2 months ago

Based on @pmorch's work. Here are some instructions for getting up and running with nix on synology NAS.

Then, I wrote the following script and saved it as /volume1/MobyX/SD2/nix/tasty-nix-init

This script sets up the necessary directories and permissions for the Nix installation.

Run this script with superuser (root) permissions.

oops() { echo "$0:" "$@" >&2 exit 1 }

Ensure the script is run as root

if [ "$(id -u)" -ne 0 ]; then oops "This script must be run as root. Please run with sudo or as the root user." fi

mkdir -p "$TEMP_DIR" || oops "Failed to create temporary directory $TEMP_DIR" chmod 1777 "$TEMP_DIR" || oops "Failed to set permissions on $TEMP_DIR."

Ensure the /nix directory exists and is bind-mounted

mkdir -p "$NIX_DIR" || oops "Failed to create Nix directory $NIX_DIR" chmod -R go+rx "$NIX_DIR"|| oops "Failed to set permissions on $NIX_DIR" chown -R "$ADMIN_UID:$ADMIN_GROUP" "$NIX_DIR"

if ! grep -q "$NIX_DIR /nix none bind 0 0" /etc/fstab; then echo "$NIX_DIR /nix none bind 0 0" >> /etc/fstab || oops "Failed to add /nix bind mount to /etc/fstab" fi

echo "Setup complete. Now running the main installer script as $USER_UID..."

su - "$ADMIN_UID" -c "export TMPDIR=\"$TEMP_DIR\"; sh /nix/tasty-nix-install"


3. Then I downloaded the official installer. `curl -L -o tasty-nix-install https://nixos.org/nix/install`
4. At this point, if you run `sudo sh tasty-nix-init`. Everything should run without a hitch. If you run into issues, read the error, dissect the problem, get sleep, and try again, then ask around. 
tastycode commented 2 months ago

@pmorch The only difference from your instructions is just packaging it to be easier for others to use, and making sure that /nix was in the fstab otherwise the nix installation would be bonked on the next reboot.

tastycode commented 2 months ago

Its probably worth mentioning why i went bananas over this issue. I love synology. One thing that's keeping me from doing more on it, is the ethereal nature of the whole configuration. Beyond the settings that would be backed up via synology internals (which relate to services that synology officially makes available), there's a whole world of 100s if not 1000s of micro-services and daemons that run through the portainer ecosystem. I get about 3 tutorials a week in my feed about how to install some service on synology via portainer. I'm fully aware of the magnitude of what you can do with portainer.

But its those instructions themselves that are precisely why i don't want to do any of it. I have to follow a set of bespoke instructions for just about every single service. There's not like a synology-community install mopidy. And that automatically sets up a portainer stack with all the correct variables and drops you into the admin interface under yournas.address/mopidy. Even if there were, there are many questions.

So, I haven't quite addressed the ability to run a command to just add a package and configure it and drop you into a UI. But the settings storage and persistence, and the blender question are things i've answered on all of my dev environments through nix.

I generally never run anything like brew install mopidy. Instead i have a git repo on my machine's , there's a nix flake in there that describes how all the machines i touch are configured. This includes what packages are installed, and how each package is configured. This basically makes huge portions of my configuration deterministic and nearly immutable. When something is broken, i can't end up in a state where fragments of previous attempts to fix the issue are lingering around causing unspeakable havoc where among the edges of subsequent issues, through interacting via terrifying and elusive nuances which might take me days of further compromising my system integrity – to even discover. Every change to my configuration is a change to the code that configures everything. Everything is in source-control. I can bissect the historical state of how things are configured. In the case of mopidy, a rich abstraction already exists that's even easier than portainer's approach. I just edit the nix configuration and add a section like this (https://github.com/TuringTestTwister/mediaserver/blob/10b54b8959cf142d1f65e9611943c938d8be7f3b/profiles/mopidy.nix#L3).

I can share huge swaths of customization and configuration between completely different operating systems. I can unify how i handle dependencies on a per-client, per-language, per-project, or per-machine basis. If i want to augment my home's security with a few extra cameras, but i am low on funds, but have plenty of raspberry pi's and webcams sitting in the dust. I can write a nix-configuration snippet to generate an ISO image that i can flash onto any of my PIs. That image might have a streamlined version of my favorite vim settings. A few yolo models to recognize my cats and interact with some cloud services that streamline my object-detection classifier checkpoints. And that's because generating ISO images, or generating container descriptions (E.g. generating a dockerfile or docker compose trees) is exactly the same semantics s my own local machine.

This is all possible through nix.

With just plain portainer, i'm reliant on replicating state via following sequences of steps with only loose predictability based on any kind of source-controllable configuration.

With nix, i'm now free to install whatever constellations of containers i want through a variety of approaches https://github.com/aksiksi/compose2nix https://docs.hercules-ci.com/arion/ https://gitlab.com/cbleslie/portainer-on-nixos

and be certain that so long as i've configured all my constellations through one of these methods, that i am free to toss my NAS into a shredder and standup a new synology NAS. Follow the instructions in this issue thread, pull down my NAS configuration from source control and run build and have my system precisely as it was (less any non-infrastructure data that was on the NAS... like... the content; movies, tv-shows, database contents etc...)

tastycode commented 2 months ago

FYI. My solution with running the installer as admin is dubious. Here's how i have to invoke nix-shell

sudo su - admin -c "nix-shell -p hello --run hello"

😭