Environment.etc vs systemd.tmpfiles

I’m currently trying to write a NixOS module where a config file has to be created.
Now I’m wondering when to use environment.etc and systemd.tmpfiles.settings since it looks like as if I could use both for this. Are there any recommendations when to use which?

To give some more context: I’m trying to improve/fix the crowdsec module and one user pointed environment.etc out (nixos/crowdsec: Use sensible defaults so that the module does not fail when simply enabling it · Issue #445342 · NixOS/nixpkgs · GitHub)

Ideally, you avoid both, and pass configuration file locations via environment variables or CLI args. But not all applications have such options.

If there is no other choice, then use environment.etc for things that must be in /etc.

And for the final fallback, there should be very few cases in which you need to create files elsewhere, but if you must, then you can use systemd.tmpfiles.

1 Like

systemd.tmpfiles is often the worst choice, because it won’t clean up paths once you remove the tmpfiles entry from your config. But if you need to quasi-declaratively create a path outside of /etc and outside the store, it may be your only choice.

2 Likes

As some others commented in https://github.com/NixOS/nixpkgs/issues/445342 I agree /var/lib is the correct path for system services that need to persistently save state somewhere.

Other applications with modules in nixpkgs use /var/lib for state information by default. A quick look at /var/lib in my NixOS setup has, for example:

  • incus puts runtime settings, storage pools, containers, virtual machines, etc. here
  • systemd has a bunch of files here. The most obviously-necessary state information I see here is timers.
  • logrotate has a state file here too

That’s not true for:

/var/lib should contain state, as per FHS spec.

Crowdsec is a special case since it likes imperatively configuring its own configuration with commands. This is inherently stateful and quite ugly; the service doesn’t integrate well with NixOS, we should not model general advice after the hacks we employ there.

(…) we should not model general advice after the hacks we employ there.

(…) I agree /var/lib is the correct path for system services that need to persistently save state somewhere.

Alright then. I’ll save the config file to /var/lib then. Thank you guys!

Haha, that’s the opposite of what I meant, but I mean, if you try to upstream this I’m sure someone will look at the exact use case and tell you if that’s the only option :wink:

Haha, that’s the opposite of what I meant (…)

Oh… Well then, in /etc/ it will be then.

but I mean, if you try to upstream this I’m sure someone will look at the exact use case and tell you if that’s the only option :wink:

I hope so xD

(According to the issue description in nixpkgs github issues) in this case the config file contains generated credentials that happens to be stored as a yaml file. Should that be considered a config file?

Depends. I’m speaking general terms, is what is being discussed in this thread an XY problem that’s secretly about that issue?

Yes, I think we are looking squarely at an XY problem. The first post lays out the two problems.

I’m currently trying to write a NixOS module where a config file has to be created.
Now I’m wondering when to use environment.etc and systemd.tmpfiles.settings since it looks like as if I could use both for this. Are there any recommendations when to use which?

Here, by itself, is a question about the best place to put a config file, in /etc via environment.etc; or some other path via systemd.tmpfiles.

To give some more context: I’m trying to improve/fix the crowdsec module and one user pointed environment.etc out ( nixos/crowdsec: Use sensible defaults so that the module does not fail when simply enabling it · Issue #445342 · NixOS/nixpkgs · GitHub )

Here is what appears to be the real question, and the one I have been focusing on. The nixpkgs issue thread seems to describe a problem with default settings in the crowdsec nixos module that causes crowdsec to attempt to create a yaml file at runtime in /etc, which does not work in NixOS. The thing is, the yaml file in question stores only generated credentials. In this situation, I want to ask whether that yaml file should be considered “configuration”?

1 Like

After thinking about what non-Nix distros do, I think that credentials file does belong in /etc. Its just that how Nix handles /etc does not easily allow an application to create a file anywhere in /etc at runtime, like @TLATER said earlier.

Maybe something that could be of interest to NixOS too. For NixNG i wrote a tmpfilesd which does clean up after itself. It doesnt support all that tmpfilesd does, but it could! See the code here: `modules/environment.nix`: support `etc` by MagicRB · Pull Request #69 · nix-community/NixNG · GitHub (as of posting this i havent pushed the latest changes, but the tool already works as pushed, i just changed the config schema later). If you need to declaratively manage a subdirectory (not /), it could work for you.

I’m not sure if i agree with this tbh. I don’t think having files in /etc causes any problems, but it gains:

  1. Reloads instead of service restarts
  2. Easy to see what comfiguration a service is running with, without havimg to dig through its systemd service
  3. With etc-overlay, runtime editing/replacing of the config files for debugging
1 Like

Not having things in /etc grants you purity since the config file is directly bound to the running service. You can’t end up with e.g. some client reading a server’s config file to figure out runtime details that then change from underneath its’ feet. It also makes multi-instance configurations harder.

The tradeoff of a bit simpler access to configuration files just doesn’t seem particularly convincing to me, and the other two benefits are edge cases that can be replaced pretty easily with an appropriate ExecReload and good application code.

NixOS’ entire point is abolishing global state. Of course you can build whatever you want, plenty of people end up using nix-ld, but doing these things is definitely not the NixOS vision. IMO having global state is almost always worse, and that’s the precise reason I like NixOS; no point in repeating the reasoning here.

/etc certainly is a fairly small evil, but that doesn’t change that it is inherently global state. Do we really need to argue the global variable thing every time this comes up? All programming language anti-pattern guides got the memo after the 90s.

2 Likes

Im not argue with you, dont see the point. But imo youre wrong :person_shrugging: