Skip to content

nixos/crowdsec: refactor architecture#446307

Draft
TornaxO7 wants to merge 1 commit intoNixOS:masterfrom
TornaxO7:crowdsec
Draft

nixos/crowdsec: refactor architecture#446307
TornaxO7 wants to merge 1 commit intoNixOS:masterfrom
TornaxO7:crowdsec

Conversation

@TornaxO7
Copy link
Contributor

@TornaxO7 TornaxO7 commented Sep 26, 2025

This PR should just refactor the crowdsec module. It's almost a total rewrite. So I recommend just to look at the new file instead of the diff.

Alright, so after looking a bit through the code, I've got the following suggestion:

Feel free to share your thoughts on my suggestions!

Closes #473707
Closes #469519
Closes #459224
Closes #458206
Closes #445342
Closes #445337

Things done

  • Built on platform:
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • Tested, as applicable:
  • Ran nixpkgs-review on this PR. See nixpkgs-review usage.
  • Tested basic functionality of all binary files, usually in ./result/bin/.
  • Nixpkgs Release Notes
    • Package update: when the change is major or breaking.
  • NixOS Release Notes
    • Module addition: when adding a new NixOS module.
    • Module update: when the change is significant.
  • Fits CONTRIBUTING.md, pkgs/README.md, maintainers/README.md and other READMEs.

Add a 👍 reaction to pull requests you find important.

@nixpkgs-ci nixpkgs-ci bot added 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` labels Sep 26, 2025
@TornaxO7
Copy link
Contributor Author

TornaxO7 commented Sep 26, 2025

Alright, I added my changes for now.

The only option which I currently have is services.crowdsec.enable = true;.
However, I'm getting the following error after restarting the service:

Screenshot_2025-09-26_22-47-36

and I'm unsure what the cause may be.

Another big change is, that there's now only services.crowdsec.settings which combines the stuff from services.crowdsec.localConfig and services.crowdsec.settings.

@nicomem may I ask if you can try out my branch if it fixes #445342 for you? Do you get the same error as I do?

@nicomem
Copy link
Contributor

nicomem commented Sep 27, 2025

Thanks, I'll try your branch and get back to you on my results.

I also got this error when I was trying to make it work on my machine but I don't remember exactly what fixed it.

Copy link
Contributor

@nicomem nicomem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some feedback from me, looking at the changes before testing it

@nicomem
Copy link
Contributor

nicomem commented Sep 27, 2025

After applying #446307 (comment) and #446307 (comment), the crowdsec service runs without failing.

However, it does not work correctly as if I call cscli parsers list, I get the following:

WARNING Ignoring file /etc/crowdsec/parsers/s00-raw/syslog-logs.yaml: lstat /var/lib/crowdsec/state/hub/parsers/s00-raw/crowdsecurity/syslog-logs.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/parsers/s01-parse/authelia-logs.yaml: lstat /var/lib/crowdsec/state/hub/parsers/s01-parse/LePresidente/authelia-logs.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/parsers/s01-parse/caddy-logs.yaml: lstat /var/lib/crowdsec/state/hub/parsers/s01-parse/crowdsecurity/caddy-logs.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/parsers/s01-parse/gitea-logs.yaml: lstat /var/lib/crowdsec/state/hub/parsers/s01-parse/LePresidente/gitea-logs.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/parsers/s01-parse/sshd-logs.yaml: lstat /var/lib/crowdsec/state/hub/parsers/s01-parse/crowdsecurity/sshd-logs.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/parsers/s02-enrich/dateparse-enrich.yaml: lstat /var/lib/crowdsec/state/hub/parsers/s02-enrich/crowdsecurity/dateparse-enrich.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/parsers/s02-enrich/geoip-enrich.yaml: lstat /var/lib/crowdsec/state/hub/parsers/s02-enrich/crowdsecurity/geoip-enrich.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/parsers/s02-enrich/http-logs.yaml: lstat /var/lib/crowdsec/state/hub/parsers/s02-enrich/crowdsecurity/http-logs.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/parsers/s02-enrich/public-dns-allowlist.yaml: lstat /var/lib/crowdsec/state/hub/parsers/s02-enrich/crowdsecurity/public-dns-allowlist.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/postoverflows/s00-enrich/rdns.yaml: lstat /var/lib/crowdsec/state/hub/postoverflows/s00-enrich/crowdsecurity/rdns.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/postoverflows/s01-whitelist/cdn-whitelist.yaml: lstat /var/lib/crowdsec/state/hub/postoverflows/s01-whitelist/crowdsecurity/cdn-whitelist.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/postoverflows/s01-whitelist/seo-bots-whitelist.yaml: lstat /var/lib/crowdsec/state/hub/postoverflows/s01-whitelist/crowdsecurity/seo-bots-whitelist.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2017-9841.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2017-9841.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2019-18935.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2019-18935.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2022-26134.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2022-26134.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2022-35914.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2022-35914.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2022-37042.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2022-37042.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2022-40684.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2022-40684.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2022-41082.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2022-41082.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2022-41697.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2022-41697.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2022-42889.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2022-42889.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2022-44877.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2022-44877.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2022-46169.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2022-46169.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2023-22515.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2023-22515.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2023-22518.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2023-22518.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2023-49103.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2023-49103.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2024-0012.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2024-0012.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2024-38475.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2024-38475.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/CVE-2024-9474.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/CVE-2024-9474.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/apache_log4j2_cve-2021-44228.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/apache_log4j2_cve-2021-44228.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/authelia-bf.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/LePresidente/authelia-bf.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/f5-big-ip-cve-2020-5902.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/f5-big-ip-cve-2020-5902.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/fortinet-cve-2018-13379.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/fortinet-cve-2018-13379.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/gitea-bf.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/LePresidente/gitea-bf.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/grafana-cve-2021-43798.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/grafana-cve-2021-43798.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-admin-interface-probing.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-admin-interface-probing.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-backdoors-attempts.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-backdoors-attempts.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-bad-user-agent.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-bad-user-agent.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-crawl-non_statics.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-crawl-non_statics.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-cve-2021-41773.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-cve-2021-41773.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-cve-2021-42013.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-cve-2021-42013.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-cve-probing.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-cve-probing.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-generic-bf.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-generic-bf.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-generic-test.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-generic-test.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-open-proxy.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-open-proxy.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-path-traversal-probing.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-path-traversal-probing.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-probing.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-probing.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-sap-interface-probing.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-sap-interface-probing.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-sensitive-files.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-sensitive-files.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-sqli-probing.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-sqli-probing.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-w00tw00t.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/ltsich/http-w00tw00t.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-wordpress-scan.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-wordpress-scan.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/http-xss-probing.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/http-xss-probing.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/jira_cve-2021-26086.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/jira_cve-2021-26086.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/netgear_rce.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/netgear_rce.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/pulse-secure-sslvpn-cve-2019-11510.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/pulse-secure-sslvpn-cve-2019-11510.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/spring4shell_cve-2022-22965.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/spring4shell_cve-2022-22965.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/ssh-bf.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/ssh-bf.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/ssh-cve-2024-6387.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/ssh-cve-2024-6387.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/ssh-generic-test.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/ssh-generic-test.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/ssh-refused-conn.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/ssh-refused-conn.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/ssh-slow-bf.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/ssh-slow-bf.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/thinkphp-cve-2018-20062.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/thinkphp-cve-2018-20062.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/vmware-cve-2022-22954.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/vmware-cve-2022-22954.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/scenarios/vmware-vcenter-vmsa-2021-0027.yaml: lstat /var/lib/crowdsec/state/hub/scenarios/crowdsecurity/vmware-vcenter-vmsa-2021-0027.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/contexts/bf_base.yaml: lstat /var/lib/crowdsec/state/hub/contexts/crowdsecurity/bf_base.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/contexts/http_base.yaml: lstat /var/lib/crowdsec/state/hub/contexts/crowdsecurity/http_base.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/collections/authelia.yml: lstat /var/lib/crowdsec/state/hub/collections/LePresidente/authelia.yml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/collections/base-http-scenarios.yaml: lstat /var/lib/crowdsec/state/hub/collections/crowdsecurity/base-http-scenarios.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/collections/caddy.yaml: lstat /var/lib/crowdsec/state/hub/collections/crowdsecurity/caddy.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/collections/gitea.yml: lstat /var/lib/crowdsec/state/hub/collections/LePresidente/gitea.yml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/collections/http-cve.yaml: lstat /var/lib/crowdsec/state/hub/collections/crowdsecurity/http-cve.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/collections/linux.yaml: lstat /var/lib/crowdsec/state/hub/collections/crowdsecurity/linux.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/collections/sshd.yaml: lstat /var/lib/crowdsec/state/hub/collections/crowdsecurity/sshd.yaml: no such file or directory 
WARNING Ignoring file /etc/crowdsec/collections/whitelist-good-actors.yaml: lstat /var/lib/crowdsec/state/hub/collections/crowdsecurity/whitelist-good-actors.yaml: no such file or directory 
──────────────────────────────────────
 PARSERS                              
──────────────────────────────────────
 Name  📦 Status  Version  Local Path 
──────────────────────────────────────
──────────────────────────────────────

@SebastianStork
Copy link

From what I have seen, the idiomatic way to make /var/lib/crowdsec and /etc/crowdsec accessible to the service, is to use the systemd service options StateDirectory and ConfigurationDirectory. This would replace ReadWritePaths and the tmpfile rules for rootDir and confDir as systemd will create those dirs automatically. I have set it like this:

systemd.services.crowdsec.serviceConfig = {
  StateDirectory = "crowdsec";
  StateDirectoryMode = "0750";
  ConfigurationDirectory = "crowdsec";
  ConfigurationDirectoryMode = "0750";
};

@SebastianStork
Copy link

People who use impermanence might appreciate DynamicUser being disabled (see nix-community/impermanence#254). The things DynamicUser does behind the scenes, we already do explicitly (at least I think so? see https://unix.stackexchange.com/questions/635027/systemd-dynamicuser-vs-user)

@TornaxO7
Copy link
Contributor Author

People who use impermanence might appreciate DynamicUser being disabled (see nix-community/impermanence#254).

Hm... should I add an option where the user can enable/disable it or should I just remove the DynamicUser option?
There was a discussion about the DynamicUser which you can read here #426875 (comment).

@TornaxO7
Copy link
Contributor Author

From what I have seen, the idiomatic way to make /var/lib/crowdsec and /etc/crowdsec accessible to the service, is to use the systemd service options StateDirectory and ConfigurationDirectory. This would replace ReadWritePaths and the tmpfile rules for rootDir and confDir as systemd will create those dirs automatically. I have set it like this:

After skimming through systemd.exec it looks like you're right. Nice one. Thanks!

@SebastianStork
Copy link

People who use impermanence might appreciate DynamicUser being disabled (see nix-community/impermanence#254).

Hm... should I add an option where the user can enable/disable it or should I just remove the DynamicUser option? There was a discussion about the DynamicUser which you can read here #426875 (comment).

Hmm, I admit that I wasn't aware of this context. I have just been disabling anywhere it bothered me. I'd like some other people to way in on this. The impermanence issue is a bug and will hopefully be fixed sometime in the future, so that shouldn't be the only reason to forgo DynamicUser

@poperigby
Copy link
Contributor

Anything I can do to help here? These options seem much more reasonable than the current ones.

I'd also like to mention I'm getting this error when trying to run it:

Error machine login for Haddock : ent: machine not found
127.0.0.1 - [Sun, 09 Nov 2025 15:55:06 PST] \"POST /v1/watchers/login HTTP/1.1 401 345.943µs \"crowdsec/v1.7.2-linux\" \"
attempt 1 out of 2
Error machine login for Haddock : ent: machine not found 
127.0.0.1 - [Sun, 09 Nov 2025 15:55:06 PST] \"POST /v1/watchers/login HTTP/1.1 401 123.611µs \"crowdsec/v1.7.2-linux\" \"
attempt 2 out of 2
Error machine login for Haddock : ent: machine not found
127.0.0.1 - [Sun, 09 Nov 2025 15:55:06 PST] \"POST /v1/watchers/login HTTP/1.1 401 100.691µs \"crowdsec/v1.7.2-linux\" \"
max attempts reached for status code 401
crowdsec init: while initializing LAPIClient: authenticate watcher (Haddock): API error: ent: machine not found

This is my current configuration: https://gist.github.com/poperigby/63ef3e5b6205b6a5e4de320bcb63838a

@TornaxO7
Copy link
Contributor Author

TornaxO7 commented Nov 10, 2025

Anything I can do to help here? These options seem much more reasonable than the current ones.

Aye, testing! What you already did:

I'd also like to mention I'm getting this error when trying to run it:

Thx!

I'll see when I'll get back to this

@AmethystNightshade
Copy link

just tested this and ran into the same error as @poperigby. i looked in the journal and it seems like it needed the api.server.online_client.credentials_path set if anything needs to pull from crowdsec servers (anything on the hub, and possibly acquisitions) in addition the console setup fails and is a bit non intuitive. you need to go to the console and grab just the token out of the command it gives you and paste just that in the console.tokenFile. it then fails as it tries to write the console.yaml into /nix/store, which of course fails due to RO filesystem

here is my configuration repo with link pointed to my system flake and the line where the crowdsec specific bits start: https://gitlab.com/Amethyst_Nightshade/nixos-flakes/-/blob/main/nixosConfigurations/tailnerd-agh.nix#L304

@TornaxO7
Copy link
Contributor Author

Alright, I'm back!

just tested this and ran into the same error as @poperigby. i looked in the journal and it seems like it needed the api.server.online_client.credentials_path set if anything needs to pull from crowdsec servers (anything on the hub, and possibly acquisitions) in addition the console setup fails and is a bit non intuitive. you need to go to the console and grab just the token out of the command it gives you and paste just that in the console.tokenFile. it then fails as it tries to write the console.yaml into /nix/store, which of course fails due to RO filesystem

Hm... this doesn't sound nice.

here is my configuration repo with link pointed to my system flake and the line where the crowdsec specific bits start: https://gitlab.com/Amethyst_Nightshade/nixos-flakes/-/blob/main/nixosConfigurations/tailnerd-agh.nix#L304

It looks like as if you've changed your repository.
Could you please update the link?

@TornaxO7
Copy link
Contributor Author

TornaxO7 commented Feb 7, 2026

Alright, I'd say we can start testing this again. I don't know exactly when I'll have time to test this on my own so I'd be happy if there would be enough testers here 👀

@TornaxO7 TornaxO7 force-pushed the crowdsec branch 3 times, most recently from 15604fe to 4b22b83 Compare February 11, 2026 23:31
@gaelj
Copy link
Contributor

gaelj commented Feb 12, 2026

So the main blocker - the need to manually run sudo systemd-tmpfiles --create is now out of the way.

Trying out every cscli subcommand shows that only these 2 are failing:

 sudo cscli hubtest list
Error: cscli hubtest list: unable to load hubtest: while creating data dir: mkdir /.cache: read-only file system

 sudo cscli setup
Error: cscli setup: open /var/lib/crowdsec/data/detect.yaml: no such file or directory

Completions on the cscli command aren't working, because it's wrapped with systemd-run. I tried to fix this with this snippet (line 785):

environment = {
  systemPackages =
    let
      cscliWrapper = pkgs.symlinkJoin {
        name = "cscli";
        paths = [
          (pkgs.writeShellScriptBin "cscli" ''
            exec systemd-run \
              --quiet \
              --pty \
              --wait \
              --collect \
              --pipe \
              --property=ExecPaths="${cfg.settings.config.config_paths.plugin_dir}" \
              --property=User=${cfg.user} \
              --property=Group=${cfg.group} \
              --property=DynamicUser=true \
              --property=StateDirectory="crowdsec crowdsec/hub" \
              --property=StateDirectoryMode="0750" \
              --property=ConfigurationDirectory="crowdsec crowdsec/acquis.d" \
              --property=ConfigurationDirectoryMode="0750" \
              -- \
              ${lib.getExe configuredCscli} "$@"
          '')
          (pkgs.runCommand "cscli-completions" { } ''
            mkdir -p $out/share
            ln -s ${cfg.package}/share/bash-completion $out/share/bash-completion
            ln -s ${cfg.package}/share/zsh $out/share/zsh
            ln -s ${cfg.package}/share/fish $out/share/fish
          '')
        ];
      };
    in
    [ cscliWrapper ];

but it asks for the sudo password on each tab press, and displays every completion in duplicate... Which isn't ideal.

Other than that, I've been using it for a month with all optional features and it works really well.

@TornaxO7
Copy link
Contributor Author

Thank you for trying out the changes and reporting any issues :)

Error: cscli hubtest list: unable to load hubtest: while creating data dir: mkdir /.cache: read-only file system

That's really weird. Why does it want to write to /.cache? Hm... I assume that it uses an environment variable which is somehow set to / per default.

Error: cscli setup: open /var/lib/crowdsec/data/detect.yaml: no such file or directory

This should be fixeable by just creating the file.

but it asks for the sudo password on each tab press, and displays every completion in duplicate... Which isn't ideal.

Hm... one idea would be to introduce an option where you can set a group name which will then be used in the sudoers-file to disable passwords for all users which are in this group to invoke the cscli without asking for a password. but I'm unsure about this approach

@gaelj
Copy link
Contributor

gaelj commented Feb 12, 2026

cscli hubtest list: the error seems to originate from this upstream line so I tried to add the creation of /var/lib/private/crowdsec/hub/.cache to the module, but I still get the same error.

data/detect.yaml: I tried to add an empty file but I get cscli setup: parsing /var/lib/crowdsec/data/detect.yaml: EOF

But really, is it really worthwile to allow cscli setup in NixOS ?

Completions: I tried allowing ALL=(ALL)) NOPASSWD: /run/current-system/sw/bin/cscli for my user but that didn't work, presumably because it's systemd that's asking for root:

 cscli ==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====                                          ─╯
Authentication is required to start transient unit 'run-p113200-i113201.service'.
Authenticating as: Gaël James,gaeljames@gmail.com (gaj)

 cscli setup
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
Authentication is required to start transient unit 'run-p112633-i112634.service'.
Authenticating as: Gaël James,gaeljames@gmail.com (gaj)
Password: 
==== AUTHENTICATION COMPLETE ====
Error: cscli setup: parsing /var/lib/crowdsec/data/detect.yaml: EOF

versus normal root elevation prompt:

 sudo lsd -la /var/lib/private/crowdsec/
[sudo] password for gaj: 

If I do sudo su, completions don't need a password.

@TornaxO7
Copy link
Contributor Author

But really, is it really worthwile to allow cscli setup in NixOS ?

Depending on what is necessary and what not, I'd say because, if I understand it correctly, you are mainly supposed to declare your system anyhow.
Unless there's something which you are only able to do with cscli setup and not with the config file, I'd say we can ignore that

Regarding the authentification: I have no idea yet on how to fix that

@gaelj
Copy link
Contributor

gaelj commented Feb 14, 2026

Some documentation on cscli setup: https://docs.crowdsec.net/docs/next/log_processor/service-discovery-setup/

@peterkmet
Copy link

Tested on: NixOS 26.05, x86_64-linux, commit 675f491

Great work on this refactor — the module is a big improvement in clarity over the current upstream version. Engine, hub collections, acquisitions (journalctl + file), CAPI community blocklist (15k IPs pulled successfully), and the iptables firewall bouncer all work well together. Declarative hub management via hub.collections is especially nice.

Issues required manual workarounds:

CAPI registration: Setting settings.config.api.server.online_client.credentials_path is not enough on a fresh install — the credentials file doesn't exist yet and the setup service doesn't auto-register. I had to run cscli capi register --file /var/lib/crowdsec/online_api_credentials.yaml manually. Note that running cscli capi register without --file silently fails on NixOS because it tries to write to read-only /etc/crowdsec/.

Firewall bouncer: registerBouncer.enable = true fails with Failed to set up mount namespacing: /var/lib/private/crowdsec: No such file or directory due to DynamicUser timing. Had to register manually with cscli bouncers add firewall-bouncer, save the key to a file, and use secrets.apiKeyPath. Also, crowdsec-firewall-bouncer.nix:93 still references the old settings.general.api.server.listen_uri instead of settings.config.api.server.listen_uri, so settings.api_url must be set explicitly.

Caddy log permissions: CrowdSec file acquisition couldn't read Caddy logs because they default to 0600 caddy:caddy. Fixed by adding users.users.crowdsec.extraGroups = [ "caddy" ] and setting systemd.services.caddy.serviceConfig.UMask = "0027" so new logs are created as 0640 (group-readable). Existing logs need a one-time chmod 640 /var/log/caddy/*.log

@gaelj
Copy link
Contributor

gaelj commented Feb 15, 2026

That's odd, @peterkmet as I don't have any issues with capi registration nor firewall bouncer registration, starting from a clean slate. And I tested that many many times.

Did you delete all prior crowdsec config and state before using the new commit ?

Would you mind sharing your config (cs and csfwb) and the logs of crowsec-setup and crowdsec-firewall-bouncer-register?

Ideally would you mind reinstalling on a cleaned system ?

after deleting /etc/crowdsec, /etc/var/private/crowdsec and /etc/var/private/crowdsec-firewall-bouncer, run systemctl start crowsec-setup and systemctl start crowdsec-firewall-bouncer-register. Finally run journalctl -xeu on these 2 services and post the output in this thread if they still fail.

EDIT

The commit you're using dates from 3 weeks from now. Current latest commit is 4b22b83. So that explains it: cscli capi register indeed didn't work at the time but it's fixed now (as well as cscli console enroll). The firewall bouncer was fixed as well.

@peterkmet
Copy link

Testing PR #446307 - commit 4b22b83 (verified via nix-prefetch-url hash match)
Tested on NixOS 26.05 (nixos-vm on Proxmox). Clean install - all CrowdSec state directories removed before each test.
What works well:

CrowdSec engine starts and runs correctly
Hub collections install declaratively
Acquisitions (journalctl + file sources) work
Parsers load and process logs correctly
Prometheus metrics work

Issue 1: Firewall bouncer register - credentials permissions
The register service runs successfully and creates /var/lib/private/crowdsec-firewall-bouncer-register/api-key.cred, but the file is owned by nobody:nogroup with 0600 permissions. The bouncer service (separate DynamicUser) cannot read it via LoadCredential, failing with:
Failed to set up credentials: Protocol error
Manual workaround:
chmod 644 /var/lib/private/crowdsec-firewall-bouncer-register/api-key.cred
chmod 755 /var/lib/private/crowdsec-firewall-bouncer-register/
systemctl restart crowdsec-firewall-bouncer
Issue 2: CAPI not auto-registered on fresh install
After a clean install, the engine starts but does not register with the Central API automatically. No online_api_credentials.yaml is generated. Manual registration is required:
cscli capi register --file /var/lib/crowdsec/online_api_credentials.yaml
After adding settings.config.api.server.online_client.credentials_path pointing to this file and restarting, CAPI works (community blocklist with ~15k entries loads successfully).
Issue 3: Caddy log permissions (minor, not PR-specific)
CrowdSec user needs to be in the caddy group to read log files. Solved with users.users.crowdsec.extraGroups = [ "caddy" ] and adjusting Caddy's UMask.
Test config used:

nix{ config, pkgs, lib, ... }:
let
  csSrc = builtins.fetchTarball {
    url = "https://github.com/TornaxO7/nixpkgs/archive/crowdsec.tar.gz";
    sha256 = "1lrf4y6ffhz0d7gg5kbq3xip7477xkdyi6m13b5l1xi3njrs33kg";
  };
  crowdsecPkg = pkgs.callPackage "${csSrc}/pkgs/by-name/cr/crowdsec/package.nix" { };
in
{
  disabledModules = [
    "services/security/crowdsec.nix"
    "services/security/crowdsec-firewall-bouncer.nix"
  ];
  imports = [
    "${csSrc}/nixos/modules/services/security/crowdsec.nix"
    "${csSrc}/nixos/modules/services/security/crowdsec-firewall-bouncer.nix"
  ];
  users.users.crowdsec.extraGroups = [ "caddy" ];
  services.crowdsec = {
    enable = true;
    package = crowdsecPkg;
    hub.collections = [
      "crowdsecurity/linux"
      "crowdsecurity/sshd"
      "crowdsecurity/caddy"
      "crowdsecurity/base-http-scenarios"
      "crowdsecurity/http-cve"
      "crowdsecurity/whitelist-good-actors"
    ];
    settings.acquisitions = [
      {
        source = "file";
        filenames = [ "/var/log/caddy/*.log" ];
        labels.type = "caddy";
      }
    ];
    settings.config.prometheus.enabled = true;
  };
  services.crowdsec-firewall-bouncer = {
    enable = true;
    settings.mode = "iptables";
    registerBouncer.enable = true;
  };
  environment.systemPackages = [ pkgs.ipset ];
}

Overall the refactor is a big improvement - declarative hub management and structured settings are great. Just the two registration issues need fixing for a fully automated fresh deployment.

@gaelj
Copy link
Contributor

gaelj commented Feb 15, 2026

Issue 1

The nobody:nogroup credentials is expected, because those services use DynamicUser. You need to run sudo systemd-run --pty -pUser=crowdsec -pDynamicUser=true -pStateDirectory="crowdsec crowdsec/hub crowdsec-firewall-bouncer-register" $SHELL to be in the same conditions as cscli and the services.

Can you please try this version of the firewall-bouncer https://pastebin.com/LYXVGU7U (or if you prefer, it's on my fork gaelj/nixpkgs branch gaelj-pkgs commit 45fb5c4d017d8ad977306e0fe8b7efa50ceaf210) ? There are some apiKeyFile-related changes in there that I haven't submitted yet which might help.

Issue 2

For capi registration to happen, settings.config.api.server.online_client.credentials_path must be supplied from the start. Set it to "/var/lib/crowdsec/online_api_credentials.yaml", the file will be created automatically by crowdsec-setup (the file must not exist before running setup). I guess the option's comment is misleading so I'll propose a fix.

EDIT:

You also need to provide the path to a file containing the enroll key that you get from app.crowdsec.net. For example:

services.crowdsec.settings.console.enrollKeyFile = config.age.secrets.${crowdSecEnrollKeySecretName}.path;

Issue 3

Yes crowdsec is going to need specific access to any logfiles it is expected to read. You might even need to add them to systemd.services.crowdsec.serviceConfig.ReadOnlyPaths.

@gaelj
Copy link
Contributor

gaelj commented Feb 21, 2026

@peterkmet since the pending changes I had have been merged in ba52755, and considering my remarks above, do you still have any problems ?

Thanks for any feedback. It would be nice to get this merged before the next NixOS release.

@peterkmet
Copy link

peterkmet commented Feb 22, 2026

@peterkmet since the pending changes I had have been merged in ba52755, and considering my remarks above, do you still have any problems ?

Thanks for any feedback. It would be nice to get this merged before the next NixOS release.

Hi James,

today I spent some time playing with new module, here are my findings:

Disclaimer

I am relatively new to NixOS, so much of my testing and current workarounds were developed through trial and error. Some of the solutions I am using might not follow NixOS best practices, and I am open to suggestions on how these should be implemented "the right way" within the module's architecture.

Tested Version:

PR: NixOS/nixpkgs#311140
Source: https://github.com/TornaxO7/nixpkgs/tree/crowdsec
Current Commit: 0417643f05359a0f9247f1233816a7f92021570d
Fetch Hash: 0f5r71vlkkjg57j4nqskmf0z2670r0l4pbcf9fybr0phrjp8fl7r

1. The "Cold Start" Issue (CAPI & Community Blocklists)

Observation: On a fresh installation (tested on a clean Hetzner VM), the engine successfully registers with CAPI (cscli capi status is OK), but no community decisions are downloaded, even after significant wait time.

Enrollment Context: I noticed that the community list is pulled immediately only if the instance is manually enrolled in the CrowdSec Console. While I see the recommendation to use services.crowdsec.settings.console.enrollKeyFile, I did not use it during this test to see the "out-of-the-box" behavior for a new user without a console account.

Problem: If enrollment is effectively mandatory to receive the community blocklist, it should be clearly documented. Ideally, the module should still provide protection for "anonymous" instances, as they are currently left unprotected by global data for an extended period after installation.

2. Caddy Logs Acquisition & Permissions Trap
Issue: CrowdSec fails to read Caddy logs despite the crowdsec user being added to the caddy group.

Technical Detail: Caddy creates logs with 600 permissions (read/write for owner only). Since files are owned by caddy and group permissions are 0, group membership for crowdsec provides no access.

Proposed Solution: The module could implement an ACL (Access Control List) via systemd.tmpfiles.rules to grant the crowdsec user read access (e.g., setfacl -m u:crowdsec:r /var/log/caddy/*.log). Alternatively, supporting log acquisition via systemd-journald might bypass these permission issues entirely.

3. Installation Resource Exhaustion (Hetzner 4GB RAM)

Observation: Attempting to install NixOS with the CrowdSec module enabled in a single initial step caused the system to hang/freeze.

Workaround: I had to perform a base NixOS install first and then add CrowdSec in a second nixos-rebuild step. This might indicate a resource spike during the initial service activation on lower-spec machines.

4. UX Improvement: Simplified Whitelisting

Current Trial/Error Method: I am currently forcing a whitelist by manually injecting YAML into environment.etc, which feels overly complex and brittle for a NixOS module:

    environment.etc."crowdsec/parsers/s02-enrich/my-whitelist.yaml".text = ''
      name: crowdsecurity/my-whitelist
      whitelist:
        expression:
          - evt.Meta.source_ip == 'xx.xx.xx.xx'
          - IpInRange(evt.Meta.source_ip, 'xx.xx.0.0/16')
    '';

Proposal: A native Nix option to abstract this (e.g., services.crowdsec.whitelist.ips = [ "..." ];) would be much more user-friendly.

services.crowdsec.whitelists = {
  management = {
    reason = "private management network";
    ips = [ "1.2.3.4" "5.6.7.8" ];
    ranges = [ "192.168.1.0/24" "10.0.0.0/8" ];
  };
};

5. Feature Suggestion: Native 3rd Party Blacklist Support

Current Trial/Error Method: I’ve implemented a custom oneshot systemd service to fetch the Turris Sentinel Greylist and import it via cscli. It works, but it’s a "hacky" way to handle it:

  systemd.services."turris-greylist" = {
    description = "Import Turris Sentinel Greylist";
    serviceConfig.Type = "oneshot";
    path = [ crowdsecPkg pkgs.curl pkgs.gawk pkgs.gnugrep ];
    script = ''
      curl -sL https://view.sentinel.turris.cz/greylist-data/greylist-latest.csv \
        | grep 'http' \
        | grep -v '^#' \
        | awk -F',' '{print $1}' \
        > /var/lib/crowdsec/turris-http.txt
      cscli decisions import -i /var/lib/crowdsec/turris-http.txt --scope ip --reason "turris-greylist" --type ban --duration 2h --format values
      rm -f /var/lib/crowdsec/turris-http.txt
    '';
  };

Proposal: Adding a declarative way to define external blacklist URLs directly in the module configuration would significantly improve the module's value as a security orchestrator.

services.crowdsec.externalBlacklists = [
  {
    name = "turris-greylist";
    url = "https://view.sentinel.turris.cz/greylist-data/greylist-latest.csv";
    refreshInterval = "2h";  # systemd timer syntax
    columnSeparator = ",";   # separator (comma, tab, space)
    ipColumn = 1;            # which column contains the IP (1st, 2nd...)
    skipLines = 1;           # skip header rows
    reason = "imported-from-turris";
  }
];

Final Verdict

The module is a great step forward and the core services work well. However, the "out-of-the-box" experience regarding community data and log permissions needs refinement to be truly production-ready for the NixOS community.

here is my crowdsec.nix https://pastebin.com/Pbqj8swE

@gaelj
Copy link
Contributor

gaelj commented Feb 22, 2026

Hi thanks for the feedback. Some quick answers from my phone.

  1. Looks like a crowdsec "feature"
  2. The simplest way is to send your caddy logs to journald. I'll look into adding an option to allow easier log file access
  3. Not sure we can do much about this in this PR. I see you use iptables, maybe switching to nftables will make a difference?
  4. There are nixos options in this module to configure the parsers and all other configurations that are then converted into yaml files in etc automatically by the module. We could add a whitelists option, but I would still encourage users to understand the upstream project's native configuration
  5. For community lists, you can try my PR crowdsec-blocklist-import: init at 1.1.0 #486054
    I haven't marked it as ready yet because it's still targeting my fork, but it's fully usable. Please also suggest any blocklists you use to the upstream if they don't list them already.

@rharish101
Copy link
Contributor

Hi, I just came across this PR. I saw that all the credentials_path options use lib.types.path. Could you relax this, so that I can use systemd credentials? Basically, right now (with NixOS unstable, not this PR), I set these:

services.crowdsec.settings.general.api.client.credentials_path = lib.mkForce "\${CREDENTIALS_DIRECTORY}/csec-creds";
systemd.services.crowdsec.serviceConfig.LoadCredential = [ "csec-creds:csec-creds" ];

This way, CrowdSec should pick up the path to the credentials using the $CREDENTIALS_DIRECTORY env var, which is set by systemd (due to the LoadCredential argument). However, if you were to force that this option be a path and not any string, I can't load the credential.

@TornaxO7
Copy link
Contributor Author

TornaxO7 commented Feb 25, 2026

Hi, I just came across this PR. I saw that all the credentials_path options use lib.types.path. Could you relax this, so that I can use systemd credentials? Basically, right now (with NixOS unstable, not this PR), I set these:

services.crowdsec.settings.general.api.client.credentials_path = lib.mkForce "\${CREDENTIALS_DIRECTORY}/csec-creds";
systemd.services.crowdsec.serviceConfig.LoadCredential = [ "csec-creds:csec-creds" ];

This way, CrowdSec should pick up the path to the credentials using the $CREDENTIALS_DIRECTORY env var, which is set by systemd (due to the LoadCredential argument). However, if you were to force that this option be a path and not any string, I can't load the credential.

From this line:

systemd.services.crowdsec.serviceConfig.LoadCredential = [ "csec-creds:csec-creds" ];

you are setting the path to csec-creds by the second csec-creds. Is the second csec-creds a placeholder for the actual path? If yes, why can't you use the actual path?

I'd really like to stick to lib.types.path because we are doing some extra work (like automatically enrolling to the online console) which would make it more complex to do if we also need to support any type of LocalCredential variables (if I'm understanding your use case correctly 👀 )

@rharish101
Copy link
Contributor

you are setting the path to csec-creds by the second csec-creds. Is the second csec-creds a placeholder for the actual path? If yes, why can't you use the actual path?

Nope, it's actually the name for the system-level systemd credential, which is set up by sops. It's hard to expose that path, because only root can read it, while crowdsec can't. Also, all of this runs in a NixOS native container (i.e. systemd-spawn). Here's the whole file: https://github.com/rharish101/nix-configs/blob/main/modules/containers/authelia.nix

@rharish101
Copy link
Contributor

I'd really like to stick to lib.types.path because we are doing some extra work (like automatically enrolling to the online console) which would make it more complex to do if we also need to support any type of LocalCredential variables (if I'm understanding your use case correctly 👀 )

You can use ${CREDENTIALS_DIRECTORY}/name-of-cred to get the path to the credential. My issue is just that lib.types.path forces absolute paths, which won't work with the CREDENTIALS_DIRECTORY environment variable.

@TornaxO7
Copy link
Contributor Author

Hm... fair enough. I'll see what I can do Let me cook.

@rharish101
Copy link
Contributor

Perhaps you could do something like what the Immich module does? See this option's description: https://search.nixos.org/options?channel=25.11&query=services.immich.settings&show=services.immich.settings. I can set the _secret attribute to just the name of the systemd credential (without CREDENTIALS_DIRECTORY), and it works.

Honestly, they should just create a lib.types.secretPath that handles credentials automatically without me having to bug module authors. 😛

overwriteInstallConfigDir =
p:
lib.optionalString (p != null) ''
cp -a ${cfg.package}/share/crowdsec/config/${p} ${config_paths.config_dir}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Nix store is read-only, so directories in the package are read-only. Something attempts to create files in the patterns directory, and this fails with a "permissions denied" message. As the "Updating hub..." print message isn't reached, I assume that cp first creates a directory without write permissions, and then attempts to copy inside it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to be attempting

mkdir ${config_paths.config_dir}/${p}
cp -a ${cfg.package}/share/crowdsec/config/${p} ${config_paths.config_dir}/${p}/

as a replacement for this cp line. This will leave the patterns themselves read only, which we'll see if that's fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me quickly replace this with install.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I just pushed some changes. Feel free to try it out again.
On my system, I'm getting a fully clean installation.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating this even while you're busy!

Copy link
Contributor Author

@TornaxO7 TornaxO7 Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome. Didn't require a big change and I try to have a little window time to code :)

@TornaxO7
Copy link
Contributor Author

Just a little info: I'm currently in my exam-session (hence don't have that much free-time and energy left).
I'll be back at the middle-end of march.
Until then: Anyone can tackle one of those problems:

and create a PR to my branch (Reviewing shouldn't take too much time).

Co-authored-by: Nicolas Mémeint <git@nicomem.com>
Co-authored-by: Jarno Pelkonen <23549925+jarppiko@users.noreply.github.com>
Co-authored-by: Yash Garg <me@yashgarg.dev>
Co-authored-by: Gaël James <gaeljames@gmail.com>
Co-authored-by: Azat Bahawi <azat@bahawi.net>
@nixpkgs-ci nixpkgs-ci bot added the 2.status: merge conflict This PR has merge conflicts with the target branch label Mar 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2.status: merge conflict This PR has merge conflicts with the target branch 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog This PR adds or changes release notes 8.has: documentation This PR adds or changes documentation 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 1-10 This PR causes between 1 and 10 packages to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux.

Projects

None yet