What does mkDefault do exactly?

I’ve googled a lot and have found little to nothing unfortunately.

Recently with this change: https://github.com/NixOS/nixpkgs/pull/97631
sandboxing was enabled by default by removing the option enableSandbox in the service nginx.
This also contains the option

ProtectHome = mkDefault true;

Though I’ve linked some nginx locations to my home directory for simple local debugging, so I don’t need sandboxing there.

The option suggests that it is somehow overridable.

What does mkDefault do here exactly?
Can I somehow set this option to false.

(I thought of an overlay, but maybe there is another/better way?).

6 Likes

This is my understanding of how this works (though I’ve only been using Nix for a couple of months, so please do correct me if I’m wrong): in your NixOS configuration you can import multiple modules via the imports list, each of which specifies a “top-level” configuration attrset. By “top-level” I mean that each module could represent an entire NixOS configuration; it has its own “programs”, “services”, etc. attributes.

Now this means that multiple modules can modify the same option. For example, you could have a module a.nix that sets services.nginx.enable = X; and another module b.nix that sets services.nginx.enable = Y;. But X is not necessarily equal to Y, causing a conflict in your configuration: should nginx be enabled or not?

To solve this, NixOS introduced a couple of functions to assign a “priority” to a value for some option. The most primitive function to do this is mkOverride (the link to the function’s definition doesn’t help a whole lot here in understanding the inner workings because its implementation does not really reveal any of its effects). mkOverride accepts two arguments: a priority (which is a number) and a value. When NixOS detects a conflict in your configuration, it uses the priority to determine which value to prefer; lower priority values are preferred over higher ones.

Now to finally answer your first question: mkDefault = mkOverride 1000;. So it assigns a (relatively low) priority of 1000 to the value you pass in, making it easy to set a value with higher priority, thus overriding the default. Another useful one is mkForce = mkOverride 50;, which sets a very high priority, thus (almost) guaranteeing that it will override values set elsewhere.

For your second question, it should be relatively simple to disable the sandboxing without using overlays, as all the enableSandbox option seemed to do (after looking at the PR you linked to) is to add some extra attributes to systemd.services.nginx.serviceConfig. And since systemd services are defined through NixOS’s declarative configuration, you can simply override their values in your own config as in the example below. Note how mkForce is really useful here to guarantee sandboxing to be disabled.

{
  systemd.services.nginx.serviceConfig = {
    ProtectSystem = mkForce false;
    ProtectHome = mkForce false;
    # ...
  };
}
23 Likes

Thank you for this extensive answer, that clears up a lot (as I’ve also wondered about the other functions in lib/modules.nix)

It’s working great btw.

1 Like

You’re welcome :slight_smile: Answering questions like this helps myself as well in understanding Nix so I’m glad it helped you too. And I’m also glad that it worked because that example was totally untested lol

6 Likes