Hacker News new | past | comments | ask | show | jobs | submit login
A Nix terminology primer by a newcomer (stephank.nl)
204 points by signa11 on June 2, 2020 | hide | past | favorite | 78 comments



I'm a longtime Ubuntu user and recently gave NixOS a try as most of our team use it. I have to admit I was highly skeptical as it all looks very complicated. The learning curve was a bit steep due to the documentation and odd terminology. But after you get going it solves so many problems. The fact you can declare you're entire desired set up in a single configuration.nix then "nixos-rebuild switch" and you're done saves so much time.


I tried to fully switch my work environment to NixOS 2 or 3 years ago. I really like the concept and I think it's a very good approach to reproducible build environments, in theory it's much cleaner than the massive data replication you get with e.g. Docker.

I only lasted for a month or two though, for a couple of reasons. The main one was that I had a lot of trouble with Python packages - Nix suggests a certain approach for dealing with them which didn't work very well for me and I didn't manage to set up an alternative that I liked. (For Haskell I loved working with Nix though!) A lot of software I use also wasn't available in the repositories and I tried to build some packages but found the Nix language a bit obtuse. The basic syntax and logic are not too hard but I still found many of the packages I used as examples very confusing.

In the end I'm back to Ubuntu using Docker whenever I need reproducible environments.


I've been trying to get a nix file running today, and the terminology definitely gets arcane very fast.

I also have the feeling that the tutorials start with the details, instead of starting with an overview so you can understand what is what.

This is guide us already very helpful and I think one should read it before the official tutorial. Thank you!


I also have the feeling that the tutorials start with the details, instead of starting with an overview so you can understand what is what.

When you are trying to be as different from everything else as wide-reachingly as Nix is, it seems to work better to build an understanding up rather than down. This seems to frustrate a lot of people because it does not give much payoff for the first few hours of learning (and that's a lot to invest to even understand what something is). The truth is that Nix is really really complicated (expect a year-long learning curve to truly "get" everything), but it's also really hard to take the more-standard approaches to building packages and managing machines seriously once all the pieces finally do all connect. Unfortunately, it kind of makes one feel like being an early adopter of git in a world where no one else uses version control. It's like, "Yes, this is way better, but I'm not going to be able to get anyone else to use it."


> Unfortunately, it kind of makes one feel like being an early adopter of git in a world where no one else uses version control.

This is a fantastic analogy.

I think it's also worth noting that git's UX is notoriously bad for newcomers. These days I'm pretty comfortable with digging myself out of any hole I might mistakenly get into with git. But when I first started using it, all I could do was trivial uses of add/commit/push/pull/merge.

I think the equivalent of "trivial uses of the basics" in Nix would be a "for this use case: just do it this way. You'll understand why later".


This is well described. Nix is fundamentally a different way to manage an OS compared to almost anything out there. While I think the ideas behind it are revolutionary and is the right way to build infra, the UX and organic growth of it makes it fairly difficult to get into - so there is unfortunately a steep learning curve. I think I sunk a solid 40 hours into building a declarative config for my own dev machine before I had a decent (but far from complete) understanding. But once you grasp it, it is quite mind blowing, and you wonder how anyone could cope with traditional mutable systems and the associated temperamental config management.

I think Guix might be the answer as a more approachable implementation of the Nix ideas, using Scheme for its config language. I haven't spent much time with it but I got going a lot quicker initially compared to Nix.


> I think Guix might be the answer as a more approachable implementation of the Nix ideas, using Scheme for its config language. I haven't spent much time with it but I got going a lot quicker initially compared to Nix.

Out of curiosity, did you tried Guix before trying Nix or vice versa?

When looking at Guix myself, all I see is that the derivations are just wrapped in parentheses otherwise they do look similar. So I'm wondering if scheme actually brings anything here, especially for someone not familiar with a functional language.

IMO Nix language isn't actually that hard, I believe the most complexity comes from nixpkgs and still not adequate documentation of it, so one needs to study its source code.


I’m probably biased in that I primarily use Emacs and like lisps. So I find guix more approachable right out the box. Learning a new language just to use an OS is quite a big ask and part of the learning hurdle of Nix.

It’s too bad that guix uses old style mailing lists for development though. I just can’t be bothered setting up myself for that mode of contribution, so I’ll continue to use NixOS for the indefinite future.


>it seems to work better to build an understanding up rather than down.

I think especially because it's so different you should start with broad concepts and examples, so that the learner can create a broad mental model where they can fill in the details. Otherwise if you hit them with a barrage of details they won't remember any of them later on, because they don't fit anywhere into a broader concept and are disorganized.

Give a few examples that do something useful, show what they're doing differently than other package managers, then break down these examples into the details.


This sounds like the Lisp curse.


> I also have the feeling that the tutorials start with the details, instead of starting with an overview

Yes. Reading the official docs, or Nix pills, gives exactly this impression.

I've read some good documentation away from the official docs on how to start using the package manager.

But understanding the overview of how to package things yourself is all wood and no trees.

There's so many moving parts in nix that knowing how they all interact, and which ones are important for your task at hand, is a headache.


Got a project or want some guidance? I can help out.


Question 1 - What is the correct way to build and install self created derivations? Right now I have a custom fish function:

  function nix-local-build
    nix-build --no-out-link \
      -E '(import <nixpkgs> {}).callPackage ./'$argv[1]' {}'
  end
To build and install something I run:

  nix-local-build some.nix
  nix-env -i [store-path-from-build]
The .nix file is in the same format as e.g. pkgs/tools/misc/bat/default.nix.

Question 2 - How to include such a derivation into configuration.nix?


Question 1: That is a reasonable way to build and install. I normally structure things like this (https://www.reddit.com/r/NixOS/comments/8tkllx/standard_proj...) where the Nixpkgs-compatible derivation is in derivation.nix and the default.nix or overlay.nix contains the "callPackage" portion.

Question 2: including such a derivation is easy with overlays or with the method above.

    drv = import ./path-to-derivation.nix;
    package = pkgs.callPackage drv {};
or something similar can work. Overlays would be slightly more re-usable, but would take a few more expressions. I'd do that if there are multiple packages you need to introduce; I normally use overlays to manage groups of interdependent packages, a "meta-package".


Thanks a lot for this :)


Just to add to what others said regarding question 2.

After you write a derivation that you can build, you need to create a module [1]. The module defines configuration options, then takes the donation and does other things such as creating service users (if needed), services and configurations.

Then you simply import it and use it.

Regarding question 1 what was suggested by others is what is the current way of doing it, but I will recommend to go through Nix Pills[2]. The author starts with making a simple derivation and then starts introducing conventions. The conventions make things more complex, but they make things more flexible. I can't wait for Flakes[3], they will standardize a lot of this, removing extra cruft and allowing things to be more composable.

[1] https://nixos.org/nixos/manual/index.html#sec-writing-module...

[2] https://nixos.org/nixos/nix-pills/index.html

[3] https://www.tweag.io/blog/2020-05-25-flakes/


Thanks for the links. Flakes seem to be a good way forward.

I've even read most Nix Pills posts, but didn't like them much. Too many details about things that I didn't understand at the time of reading, so the why got lost. In Nix you get a lot of details, what is missing is often the why and how. For example I wanted to have a CLI command available with a binary build, finding out how to add the CLI tool to the package through wrapProgram in postInstall wasn't fun. Overall Nix is awesome, but here and there it is hell of a lot frustrating. After reading so many hours I should not have to ask how to install a custom package the right way.


Overlays can be very helpful for this type of thing.

I have overlays in ~/.config/nixpkgs/overlays.nix (though you do this various ways)

My overlay file has the form:

let my-packages-overlay = self: super: { foo = super.callPackage ./path/to/package.nix {} } in [ my-packages-overlay ]

Then you can just nix-env -iA your-package.

See: https://nixos.wiki/wiki/Overlays


> Then you can just nix-env -iA your-package.

This is what always gets me stuck. It seems like lots of tutorials assume you're installing packages by hand still. For me, the whole reason I'm using nix is so that I can use the declarative package management.

I get having local dev dependencies on a per-project basis and running a nix shell to make those dependencies available in your development environment.

But it's just confusing to me how many tutorials suggest running nix-env -i to imperatively install a package. Why would I do that instead of taking advantage of the joys of declarative package management?


Because Nix is a language there are many ways of accomplishing the same thing. Some ways are easier, some require more work. For example if you make a derivation in your home, it is easy to install it with nix-env from there, and you are done, but if you want to include it in your configuration, you typically would create an overlay that includes your package in nixpkgs. Then you can list the package. If your derivation requires creating a configuration, service etc. On top of that you will also need to create module that specifies configuration options and configures the application.

So in many cases you are told to use nix-env, because the person just answered how to write a derivation and didn't go further than that.

I think flakes (still work in progress), will help here, because it defines a standard that supposed to do all of that in one file that is easily composable.


I've never used nix-env on NixOS. I really think that command only exists as a bridge for people used to more traditional OS's. I think there is a space for it - if you don't want to spend time building your user configuration declaratively, just install what you need and get going.


I wish I understood how to bring new things to Nix. Like, if I have some language or framework with a bunch of plugins and modules, and I have the freedom to bend the framework a bit in order to get it working with Nix, then what is the best path for doing that? All of the documentation I've read seems like it's been written by folks who deeply understand not just each different language, but also some sort of central Nix philosophy.


I think one way to look at nix is that it want to act(in good way) the central source of truth for deterministic package, and one way it goes about it is by doing the step for both system level packages, and language level packages(for example, if you approach a nodejs app, you will lock both the nodejs version, the underlying openssl or other headers lib used by node-gyp, and the node_module packages itself in nix) and that is one of the main flow of nix, take a existing project/app/software, and convert it to usable nix packages, and that work even in edge cases like:

- app that is binary , so you can't build it from source, but is using dynamic libraries, then you can use autoPatchelfHook to tell nix to patch the binary to swap out the libraries to nix's version

- app that uses a lot of hard coded file system path that you would prefer not to patch them all out, then you can use buildFHSUserEnv to package/run the application/package in full FHS-compatible scenario

but the main point is that, nix is extreme in its approach, and the best approach in my opinion, is to do swapping step by step, ex:

you want to convert a existing project to nix, lets say nodejs

- you add the main deps in the default.nix (nodejs, yarn, high level utility needed to build)

- use sandBox false to allow building the app with yarn/npm in internet accessible(by default nix uses sandBox which disallow internet inside build step, which causes issue like npm install not working, etc)

- confirm working, then start using tool likes yarn2nix, other similar, and convert the packages itself to a usable set of nix packages

though I do agree that nix have the knowledge bias issue, and alot of my learning of nix involve me looking at the nixpkg sources itself and sometime even the nix's code


The trouble is that it's not just that nix is opinionated, it's that much of the complexity is in patterns and conventions that are implemented in nix. Learning everything about everything about the Nix toolchain is only one third of the battle; the rest is learning all of the conventions and patterns for writing Nix expressions, and these conventions and patterns are subject to variance between target languages. This is made terribly difficult because the language is dynamically typed and it's almost impossible to know about the "shape" of any given parameter because there is no way to know where it is defined in the enormous nixpkgs repo except to grep around and try to find the place where the caller is invoked, what is passed into it, and trace that back to an original import statement (and from there to a file on disk and the corresponding definition). That long tedious process is the hot path for developing in Nix.


Very much agreed; nix is its own world, which makes it really hard to get into. I wish someone had written "nix but in python" (or bash, or whatever) that still used a nix-store equivalent, kept the overall design and the immutable and reproducible packaging, still connected everything by hash, did all the hydra-style build infrastructure.. but didn't use nix-the-language, and made an explicit effort to use more conventional language wherever reasonably possible. Ideally, it'd even let you write expressions in arbitrary languages; it should be perfectly possible to say, "here is a directory containing 'inputs' and 'output' subdirectories based on your declared dependencies; place any build steps you want in build.sh, so long as they deterministically populate 'output' from the package directories in 'inputs'" (and then run the build a few times, without network access, to make sure). I don't see anything in nix that actually needs nix-the-language, or even a functional language at all, and I think nix-the-package-manager would be far more accessible if they'd not tied nix-the-language to everything.


> I wish someone had written "nix but in python" (or bash, or whatever) that still used a nix-store equivalent, kept the overall design and the immutable and reproducible packaging, still connected everything by hash, did all the hydra-style build infrastructure.. but didn't use nix-the-language, and made an explicit effort to use more conventional language wherever reasonably possible

Guix?


I haven't dug in far enough to be confident in this, but I think they basically just did a straight one-to-one replacement nix->guile? Which is certainly better than creating a whole one-off language just for the purpose, but is still tied to the one language, requires you to wrap your head around a hole different mental model and programming environment, and importantly to me, uses a language that I'm not familiar with in a paradigm that I don't frequently touch. I mean, I'm barely a programmer, let alone a LISPer; I can write Arch PKGBUILDs and Alpine's APKBUILDs and BSD port/package Makefiles, but the moment that creating a package requires using any significant amount of a real, non-trivial programming language, complete with local idioms, I'm going to get stuck really quickly. A lot of my frustration with nix is that everything is a special case. There's no way to "configure && make install"; you have to use some special nix module that knows how to handle autoools/cmake/whatever. And I understand why this is really great as long as you're doing something expected, but the first package I tried to write didn't fit into any of the obvious patterns so I was stuck in the deep end with no obvious way to just write the three shell commands that I needed to actually build the package.


Typically getting languages to talk with each other is very difficult and onerous for the programmer unless the languages were built to interface with each other, and in this case, that probably means "different syntax frontends for a common semantic backend".

Even if you build Python-like and JS-like and etc syntax frontends for a hypothetical common backend, they will only be syntactically similar, but the semantics and standard libraries will be different than Python, JS, etc so there's really very little to be gained here.

And maybe it's even worse, since the whole goal is to allow a Python-like frontend to reference functions and variables defined by other frontends, the authors will probably have to understand certain aspects of all frontends. if those frontends are sufficiently similar and familiar (e.g., Python and JS) then there isn't much of a problem, but if you throw in an obscure syntax like Nix this becomes harder.


I'm not saying that I want library/module integration; I want nix to be able to build a package by creating a working directory with a set of input directories and an output directory, and then running an arbitrary script to convert the inputs into the output.


If I understand correctly you can do that today (nix builds with bash scripts by convention but there's no reason you can't ask it to use Python or whatever or call into Python/etc from bash). But that's all orthogonal to the expression language.


I think functional languages are a good fit for the problem though. Given some input, compute a static build plan. It's very rare that you need to do imperative-style computation for that. What I think Nix really needs is some kind of static typing, because right now if you make a type error the error might appear in a completely random location, making it difficult to debug.


I don't think this is any more true for this problem space than other problem spaces. The "pure functional package manager" property doesn't come from the functional expression language, but from the thing that takes the static build plan and executes it. You could make these build plans in Python (or Starlark https://go.starlark.net) very elegantly and with the massive added bonus that they are intelligible to a much broader audience, and Python still allows for a very functional style. The only caveat I would add is that the Nix expression language has really nice support for multiline strings and Python still hasn't figured that out. Lastly, Python also supports type annotations and even a type checker (although the type checker leaves a lot to be desired, such as basic types or callbacks that take kwargs so it might be better off to implement one's own type checker).

But 100% agreement that Nix needs a type checker!


Take this example build file in Mozilla's custom, Python-based build system: https://searchfox.org/mozilla-central/source/gfx/skia/moz.bu...

The language is imperative, and the result is fully declarative. A pure functional description of this logic would worsen understanding instead of improving it, I believe, because when your conditionals affect multiple output variables, you have to duplicate the condition in multiple places.


Looking at the code, I don't see any advantage of using imperative language here. All the conditions used there are already available and don't change during the execution of that code. So the conditionals would be nearly identical in functional language.

Nix advantage here would be that is lazily evaluated, so there would be an additional benefit that only conditionals that are used are evaluated.

Functional benefit of Nix would be that Nix would know that a package doesn't need to be rebuilt if no inputs changed.

Side note Mozilla actually uses Nix internally, it appears that it is used for Rust and Firefox and most likely other things[1][2]

[1] https://github.com/mozilla/nixpkgs-mozilla

[2] https://github.com/mozilla/release-services


> Looking at the code, I don't see any advantage of using imperative language here. All the conditions used there are already available and don't change during the execution of that code. So the conditionals would be nearly identical in functional language.

Yes, except that I can read this and I can't read nix. That's probably based on background, but more people are familiar with imperative than functional languages.

> Nix advantage here would be that is lazily evaluated, so there would be an additional benefit that only conditionals that are used are evaluated.

Agreed, although that's unlikely to be unique to nix?

> Functional benefit of Nix would be that Nix would know that a package doesn't need to be rebuilt if no inputs changed.

As would anything that can compare hashes. Or heck, make(1) can do as much.


> As would anything that can compare hashes. Or heck, make(1) can do as much.

Of course, language like Python is Turing Complete so you could implement the same functionality . You could also add functions that behave and perform operations lazily.

But you're missing the point though, those are properties that Nix provides natively that are tuned to what is required for this domain. Because the only side effect in nix is a derivation, and because language is lazily evaluated it is made for this purpose.

If you would use for example Python, you would need to write wrappers that would provide that behavior and it no longer would be Python, it would be some kind of DSL written in Python at that point and the risk then would be that it would be very easy to introduce iterative code that's not functional and not lazily evaluated (kind of like it happens with Chef recipes).

The Nix Language actually is not the problem here, the language is fairly simple, the biggest difficulty is actually nixpkgs which is huge and poorly documented. You often have to look at its code to understand what's going on. If it was written in Python you would have the same issues.

There is one thing that Nix Language could do better, a lot of people wish it was a typed language, because if it was typed it would be much easier to find a definitions, and wouldn't require as much of greping the code. But python again wouldn't help here.


Nix is also Turing complete, and Python (to my knowledge) can also run in a side-effect-free context through various methods (it’s easy enough to enforce during code review but there are technical solutions as well). There’s also Starlark which is a sealed, embedded Python-like which is NOT Turing complete and which can also avoid side effects (evaluating to a derivation, if you like).

Nix may be simple but it’s unfamiliar, and you’re already asking people to understand a novel package management system and everything about everything about their entire dependency tree, and these unknowns are collectively more confounding than the sum of their parts.

Python would help because it is familiar and gradually typed. That said, I’m open to any language that satisfies those properties (maybe also “composes nearly from expressions”).


I don't believe Nix is Turing complete, unless you include ability of running python or bash script.

Regarding the rest of your first paragraph, that's essentially what I said, you can write side effect free code in python, but it's so easy to introduce side effects if you're not paying attention.

I'm saying though that nix language isn't the hard part about nix, but perhaps you're right and it is one extra difficulty that just makes things harder.

But take a look at most o Nix derivations, majority of them end up being just an attribute set (aka dictionary, map etc in other languages)

Take look at https://nixos.org page (they changed it after this submission was posted, and it is better than the old page at showing what Nix can do)


Nix-the-language is the easiest and most pleasant part of Nix. It's basically JSON with recursion and variables.

Grafting Python on top of the idiosyncrasies of how Nix does things would be a nightmare of impedance mismatch.


I have a different subjective experience.

The mixing between parenthesis and braces and the lack of standard indentation makes some derivations really hard to read.

I can't give you an example right now, but I've been looking at the nixos modules that deal with creating NixOS images lately. So you can get an idea of the part of the codebase that gave me this experience.


> The mixing between parenthesis and braces and the lack of standard indentation makes some derivations really hard to read.

For sure, you're absolutely right. I'm just saying that doing that in Python would have exacerbated the problem, not made it better. (Imagine someone taking the full power of Python and unleashing it on the derivation writing process, yuck.)


I don't think Python would be a problem. I've used it for lots of other similar configuration-esque tasks (which is what the Nix expression language is doing--producing a configuration payload that describes how to build a target) and it works well. If you really want to constrain it, there is Starlark (https://go.starlark.net) for exactly this purpose, but in practice I haven't really needed these constraints.


Well, if I'd have it my way, I would write the derivations in Haskell. That way, I would have a clearer picture of the different data types that flow through the build process.


Aside from the official docs and wikis, I find the nixpkgs repository[1] extremely useful as a reference and is definitely one of the things that make me love Nix. It helped me a lot to get started.

Any official package from Nix belongs to this single repository, making it easy to see what other packages are doing. If I want to see how python packaging is done, I simply search "python" in the nixpkgs repository.

It's also easier to grasp what is going on in nixpkgs than other packaging systems. The Nix expression language offers better readability than say, RPM spec files. Meanwhile the nixpkgs repository includes support for numerous build systems and frameworks. This combined allows you to create packages with minimal effort most of the time.

[1]: https://github.com/NixOS/nixpkgs


If you want to know what the result could look like I would recommend the following blog post by Christine Dodrill where she shows off her setup for working with Go code in Nix: https://christine.website/blog/i-was-wrong-about-nix-2020-02...

It's more focused on the result then on how you get there, but that result really impressed me.


Are you stuck with the interface for the user? Based on what I saw with python and postgres the latest and greatest seems to be:

yourthing_custom = yourthing.withPackages(ps: [ps.plugin1 ps.plugin2 ] )

Or are you stuck with how to implement it?


mkDerivation is a nice hammer to try


I've started writing tutorials at https://nix.dev/ to help people set up their development environment and get up and running quickly.

Disclaimer: the owner of https://cachix.org


Feel free to request a tutorial athttps://github.com/domenkozar/nix.dev/issues


I guess the ideal, for me, would be to have a service where I could upload a Nix file, and then have it generate a server from that. Darklang may be working with the general idea, but I'd like to see it for Nix too.


People mentioned NixOps (I personally think it is weaker part of Nix, but it is still good for specific use cases)

There's also another option, nixpkgs actually has a functionality to generate ec2 image, basd on your configuration.nix[1]

You can also generate other images[2]

[1] https://github.com/NixOS/nixpkgs/blob/master/nixos/maintaine...

[2] https://github.com/nix-community/nixos-generators

edit: I believe you can use [2] even for AWS images, the raw and qcow2 should work on EC2 as well, the [1] is including some additional settings that make NixOS work better there, although there's nothing stopping you from adding these to your own configuration.nix

Also, this is not really a fault of Nix, but in EC2 if you import image it has to go through their conversion mechansim, which takes about 10 minutes :( A kind of workaround around it is to have another instance with attached extra EBS drive, use dd to write raw image on that disk. Then disconnect the EBS, create a snapshot of it and convert the snapshot to an AMI.


Morph is another great alternative to NixOps (well, it's not a replacement per se, but it's easier to use and lightweight in comparison to NixOps). It's basically just a really nice wrapper that allows you to easily deploy smaller herds of servers (~100 and less). I wholeheartedly recommend trying it out https://github.com/DBCDK/morph


I tried to use nixos-generators recently and the experience wa frustrating. For example, I tried to generate an image in the `do` format (DigitalOcean) and a few other formats. Every time, the script (`nixos-generate`) finished running and didn't produce any output.


Hmm frankly I did not use nixos-generator before writing this post, and only generated EC2 images.

But I just tried, and it did work for me. The generated image was provided as the last line of the output.

It looked like this:

    Making image hybrid...
    /nix/store/ra02s6nmhfklmsrmhkd960xdqpwghgak-nixos.iso/iso/nixos.iso
What OS you run it on? I run this on NixOS 20.03 on VirtualBox, I needed to have "Enable Nested VT-x/AMD-V" since the process spins a qemu to finalize the image.


When I didn't get any output, I ran it in Ubuntu 18 on a Linode VPS. But I tried to generate different formats: do, qcow, vmware.


Strange that there was no output or even errors.

BTW: I believe NixOS image generation can be run only on NixOS machine, because it needs to run a VM and that requires some kernel modules to be loaded. At least I never was able to made it work on OS X.

The nixos-infect code though will turn your Ubuntu installation into NixOS, so you might try to boot to your Ubuntu machine, convert it to NixOS and I'm hoping then nixos-generate might start working.

Note though that "do" didn't work either for me, and I didn't look to investigate why, I figured out that maybe it was because I was running it on machine on VirtualBox and not DO.


Have you tried https://github.com/elitak/nixos-infect ? Works like a charm (with DO). It's a oneliner, you don't need to fiddle with anything. If it won't work from the user config option, just paste it in the live VPS and it will rebuild itself.


I haven't. I was trying to use nixos-generators, because at some point I want to generate a custom, stripped down image of NixOS. But until then, I might use nixos-infect, if it gets me a running instance of DO quicker.


It's super easy and works every time. You might want to change NIX_CHANNEL=nixos-19.09 to NIX_CHANNEL=nixos-20.03 since 19.09 is the previous stable version. I use nixos-infect along with Morph so I don't care about the custom images that much - a fresh/bare NixOS is all I need to build, push and deploy the actual configuration through Morph.


Didn't know about Morph. Thanks!


You're describing something a little like NixOps, which is something like a cross between nix and terraform.


Yep, that's nixops, although it's a command-line application.


NixOps + the kind of money mainstream projects get would be really nice. Sadly NixOps is a lil rough around the edges. I like using it for my projects already though. I manually provision on DO instead of letting the tool do that.


Agree, they approached this by creating a common interface to provision VMs. The good part is that you can deploy the image to different cloud providers with minimum changes. The bad think is that it is utilizing the common components among all providers, that means you essentially can just deploy VM and that's it. No autoscaling etc.


Just a minor footnote. My interest in Nix is not high and what there is motivated mostly by the existence of NixOS. Why do I have any interest in NixOS?

We build and distribute Ardour (a cross-platform open source DAW) in a single package that runs on every Linux distribution that has libc, libstdc++, and some version of Xlib.

Every Linux distribution that is, except NixOS. They decided to patch the runtime linker so that the approach usable on every other Linux distro breaks there.

This says something about NixOS, and presumably Nix too, though I'm not sure what.


Hi Paul, thanks for Ardour.

For anyone curious, this wiki page describes how to package and run some precompiled binaries on NixOS, particularly the section "The Dynamic Loader": https://nixos.wiki/wiki/Packaging/Binaries

NixOS tries to insist that programs reference only other paths within the nix store (e.g. /nix/store/9rabxvqbv0vgjmydiv59wkz768b5fmbc-glibc-2.30/lib64/ld-linux-x86-64.so.2 which is a specific version built by a specific compiler, rather than /lib64/ld-linux-x86-64.so.2). This is the source of the per-program isolation that enables all the nifty features of NixOS.

NixOS _does_ make exceptions to that though, for example providing both /bin/sh and /usr/bin/env at those paths.


The key point here is that we want to package things in a distro-independent way. In our distro-independent package there is no store and hence on nixOS it won't run.

Note that the way we do things is not unique - Firefox has been packaged this way by the Mozilla Foundation for years. We consider ourselves closer to a "traditional ISV" than merely the provider of source code to the open source community (though obviously, we play the latter roll too).

We don't have the resources to spend on a nixOS-specific package, nor the desire. Fortunately, of course, nixOS users can create suitable packages for nixOS, and I think they are.

It just says something that out of the myriad flavors of Linux, nixOS is the only one that has broken this rather old concept for packaging software from ISVs.

But please, carry on! Seems interesting enough.


I didn't think NixOS patched the runtime linker (though I could definitely be wrong).

They do eliminate any ability to automatically find libraries, and the dynamic loader does not exist at the path where it exists on most other distros, which means binaries linked elsewhere will not run unmodified on nixos.


To expand a bit on this for people not familiar with Nix: the dynamic linker is treated as any other dependency and therefore stored in the Nix store, using the derivation's hash as part of the store path.

The binary's .interp section indicates which dynamic linker must be used. On a regular Linux distribution, you will find that this is a global path:

    $ readelf -p .interp $(which cp)
    String dump of section '.interp':
      [     0]  /lib64/ld-linux-x86-64.so.2
No global library paths such as /lib or /lib64 exists on NixOS. This is one of the reasons why binaries compiled on other Linux distributions, such as Ubuntu, do not work out of the box. And you have to use patchelf to change the dynamic loader's path.

Instead, the dynamic loader of the glibc version that a program was built against is used:

    $ readelf -p .interp $(which cp)
    String dump of section '.interp':
      [     0]  /nix/store/jx19wa4xlh9n4324xdl9rjnykd19mmq3-glibc-2.30/lib/ld-linux-x86-64.so.2


Why aren't there symlinks for things standard linux directories, a bit like current-system in the user environment? Why go through the effort of patching the actual binary? Doesn't that cause enormous problems with signed stuff?

Edit: I assume you can't do it very well system-wide because individual packages might need conflicting versions. Okay. Has something like runtime injection been considered? What are the trade-offs here? (I think it's fairly obvious that I'm not very familiar with the whole matter yet).


I've not heard of anything patched outside of paths being changed by patchelf. This is done because any dependencies are being stored inside the nix store under a hash of their dependency trees, which allows for multiple versions of the same dependency to exist without conflict. You should find that the NixOS community has no problem with producing the nix file to make NixOS support possible for your open source DAW.


I like the idea of NixOS. It's somewhat hurt by the fact that it's not a first-class OS at most VPS providers. It also doesn't seem to be quite as capable as Ansible yet for configuration. If there isn't a provided variable for the setting you want, there's not a generic way to add a line to a configuration file, for example. (I might be wrong about this!)


Both of these are true, but I find that the second, at least, isn't as much of a problem as you'd expect. Most modules that configure services give you the ability to specify complete config files, which you can build whatever higher level structure you like on top of.

For example, the built-in firewall is fairly basic (at least for running on a router; it does nearly everything you'd need for most desktop and server applications). I run NixOS on my router, so I needed something more. So, I wrote https://github.com/thequux/nix-zone-firewall (note: the readme is slightly out of date, but it does give you the gist of it). First, I built a way to declaratively put rules in different chains (core.nix), and then I built a zone-based firewall on top of that. I then have another layer of configuration options in my router's config (not that repo) to be able to spread configuration across multiple files.

Even though this was the first significant bit of Nix that I wrote, I still was able to put the entire thing together in a single evening after work.


You're right in general, but most nixos modules have an `extraConfig` field where you can put whatever you want.


Have you seen https://github.com/elitak/nixos-infect ? It allows you to easily re-create/infect existing distros into NixOS. Super helpful, works as a charm (tested on DO).


Thanks. I also found this Cheatsheet from the NixOS Wiki with comparisons to apt-get to be useful: https://nixos.wiki/index.php?title=Cheatsheet&useskin=vector

I would also love to see a tutorial for beginners on Linux that covers common tasks like viewing changelogs, creating a simple package, and pinning multiple dependencies in an environment.


I'm actually aiming to do that in a series of post in the upcoming month(s)... I've started with a noob-friendly (written by a noob!) introduction and plan to continue with installer, basic package creation, module creation, discussing how to do rollback, what are generations etc. etc. ... I did some presentations on NixOS and these topics so I'd like to distill that into a short and easy to grasp blog posts @ https://nixos.online - feedback is more than welcome! Maybe I could also include my own cheatsheet, which is refurbished version of the "official" one, but just for the basic commands in direct comparison to Debian-like distros.


A straight-up cheatsheet would be useful.

I didn't find the direct comparison to apt to be useful before installing nixos, to be honest, but as primarily a `nix-shell --pure` user who just got nixos installed on my server, I suppose I might revisit it...




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: