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?
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.
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.
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.
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
(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?
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.
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”?
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.
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.