···187188- `services.monero` now includes the `environmentFile` option for adding secrets to the Monero daemon config.
18900190- The new option [networking.ipips](#opt-networking.ipips) has been added to create IP within IP kind of tunnels (including 4in6, ip6ip6 and ipip).
191 With the existing [networking.sits](#opt-networking.sits) option (6in4), it is now possible to create all combinations of IPv4 and IPv6 encapsulation.
192
···187188- `services.monero` now includes the `environmentFile` option for adding secrets to the Monero daemon config.
189190+- `services.netbird.server` now uses dedicated packages split out due to relicensing of server components to AGPLv3 with version `0.53.0`,
191+192- The new option [networking.ipips](#opt-networking.ipips) has been added to create IP within IP kind of tunnels (including 4in6, ip6ip6 and ipip).
193 With the existing [networking.sits](#opt-networking.sits) option (6in4), it is now possible to create all combinations of IPv4 and IPv6 encapsulation.
194
···31 options.services.netbird.server.signal = {
32 enable = mkEnableOption "Netbird's Signal Service";
3334- package = mkPackageOption pkgs "netbird" { };
3536 enableNginx = mkEnableOption "Nginx reverse-proxy for the netbird signal service";
37
···31 options.services.netbird.server.signal = {
32 enable = mkEnableOption "Netbird's Signal Service";
3334+ package = mkPackageOption pkgs "netbird-signal" { };
3536 enableNginx = mkEnableOption "Nginx reverse-proxy for the netbird signal service";
37
+72-28
nixos/tests/netbird.nix
···7 ];
89 nodes = {
10- clients =
11 { ... }:
12 {
13 services.netbird.enable = true;
···15 };
16 };
1718- # TODO: confirm the whole solution is working end-to-end when netbird server is implemented
19- testScript = ''
20- start_all()
21- def did_start(node, name, interval=0.5, timeout=10):
22- node.wait_for_unit(f"{name}.service")
23- node.wait_for_file(f"/var/run/{name}/sock")
24- # `netbird status` returns a full "Disconnected" status during initialization
25- # only after a while passes it starts returning "NeedsLogin" help message
26-27- start = time.time()
28- output = node.succeed(f"{name} status")
29- while "Disconnected" in output and (time.time() - start) < timeout:
30- time.sleep(interval)
31- output = node.succeed(f"{name} status")
32- assert "NeedsLogin" in output
33-34- did_start(clients, "netbird")
35- did_start(clients, "netbird-custom")
36- '';
37-38 /*
39- `netbird status` used to print `Daemon status: NeedsLogin`
40- https://github.com/netbirdio/netbird/blob/23a14737974e3849fa86408d136cc46db8a885d0/client/cmd/status.go#L154-L164
41- as the first line, but now it is just:
4243- Daemon version: 0.26.3
44- CLI version: 0.26.3
45- Management: Disconnected
00046 Signal: Disconnected
47 Relays: 0/0 Available
48 Nameservers: 0/0 Available
···50 NetBird IP: N/A
51 Interface type: N/A
52 Quantum resistance: false
53- Routes: -
0054 Peers count: 0/0 Connected
000000000055 */
0000000000000000000000000000000000000000000000000056}
···7 ];
89 nodes = {
10+ node =
11 { ... }:
12 {
13 services.netbird.enable = true;
···15 };
16 };
170000000000000000000018 /*
19+ Historically waiting for the NetBird client daemon initialization helped catch number of bugs with the service,
20+ so we keep try to keep it here in as much details as it makes sense.
02122+ Initially `netbird status` returns a "Disconnected" messages:
23+ OS: linux/amd64
24+ Daemon version: 0.54.0
25+ CLI version: 0.54.0
26+ Profile: default
27+ Management: Disconnected, reason: rpc error: code = FailedPrecondition desc = failed connecting to Management Service : context deadline exceeded
28 Signal: Disconnected
29 Relays: 0/0 Available
30 Nameservers: 0/0 Available
···32 NetBird IP: N/A
33 Interface type: N/A
34 Quantum resistance: false
35+ Lazy connection: false
36+ Networks: -
37+ Forwarding rules: 0
38 Peers count: 0/0 Connected
39+40+ After a while passes it should start returning "NeedsLogin" help message.
41+42+ As of ~0.53.0+ in ~30 second intervals the `netbird status` instead of "NeedsLogin" it briefly (for under 2 seconds) crashes with:
43+44+ Error: status failed: failed connecting to Management Service : context deadline exceeded
45+46+ This might be related to the following log line:
47+48+ 2025-08-11T15:03:25Z ERRO shared/management/client/grpc.go:65: failed creating connection to Management Service: context deadline exceeded
49 */
50+ # TODO: confirm the whole solution is working end-to-end when netbird server is implemented
51+ testScript = ''
52+ import textwrap
53+ import time
54+55+ start_all()
56+57+ def run_with_debug(node, cmd, check=True, display=True, **kwargs):
58+ cmd = f"{cmd} 2>&1"
59+ start = time.time()
60+ ret, output = node.execute(cmd, **kwargs)
61+ duration = time.time() - start
62+ txt = f">>> {cmd=} {ret=} {duration=:.2f}:\n{textwrap.indent(output, '... ')}"
63+ if check:
64+ assert ret == 0, txt
65+ if display:
66+ print(txt)
67+ return ret, output
68+69+ def wait_until_rcode(node, cmd, rcode=0, retries=30, **kwargs):
70+ def check_success(_last_try):
71+ nonlocal output
72+ ret, output = run_with_debug(node, cmd, **kwargs)
73+ return ret == rcode
74+75+ kwargs.setdefault('check', False)
76+ output = None
77+ with node.nested(f"waiting for {cmd=} to exit with {rcode=}"):
78+ retry(check_success, retries)
79+ return output
80+81+ instances = ["netbird", "netbird-custom"]
82+83+ for name in instances:
84+ node.wait_for_unit(f"{name}.service")
85+ node.wait_for_file(f"/var/run/{name}/sock")
86+87+ for name in instances:
88+ wait_until_rcode(node, f"{name} status |& grep -C20 Disconnected", 0, retries=5)
89+ ''
90+ # The status used to turn into `NeedsLogin`, but recently started crashing instead.
91+ # leaving the snippets in here, in case some update goes back to the old behavior and can be tested again
92+ + lib.optionalString false ''
93+ for name in instances:
94+ #wait_until_rcode(node, f"{name} status |& grep -C20 NeedsLogin", 0, retries=20)
95+ output = wait_until_rcode(node, f"{name} status", 1, retries=61)
96+ msg = "Error: status failed: failed connecting to Management Service : context deadline exceeded"
97+ assert output.strip() == msg, f"expected {msg=}, got {output=} instead"
98+ wait_until_rcode(node, f"{name} status |& grep -C20 Disconnected", 0, retries=10)
99+ '';
100}
···4849stdenv.mkDerivation (finalAttrs: {
50 pname = "ipxe";
51- version = "1.21.1-unstable-2025-07-30";
5253 nativeBuildInputs = [
54 mtools
···66 src = fetchFromGitHub {
67 owner = "ipxe";
68 repo = "ipxe";
69- rev = "f7a1e9ef8e1dc22ebded786507b872a45e3fb05d";
70- hash = "sha256-dNnZH6ENxx3K2lAIE0B8mLjOo05D/TBguarrGrxXozc=";
71 };
7273 # Calling syslinux on a FAT image isn't going to work on Aarch64.
···4849stdenv.mkDerivation (finalAttrs: {
50 pname = "ipxe";
51+ version = "1.21.1-unstable-2025-08-07";
5253 nativeBuildInputs = [
54 mtools
···66 src = fetchFromGitHub {
67 owner = "ipxe";
68 repo = "ipxe";
69+ rev = "8460dc4e8ffc98db62377d1c5502d6aac40f5a64";
70+ hash = "sha256-Xk1lbExR4dyiba4tF0Dm9/KtTVxc78Fs8gjmZU7pdpI=";
71 };
7273 # Calling syslinux on a FAT image isn't going to work on Aarch64.
+3-3
pkgs/by-name/ka/kardolus-chatgpt-cli/package.nix
···9 # "chatgpt-cli" is taken by another package with the same upsteam name.
10 # To keep "pname" and "package attribute name" identical, the owners name (kardolus) gets prefixed as identifier.
11 pname = "kardolus-chatgpt-cli";
12- version = "1.8.5";
1314 src = fetchFromGitHub {
15 owner = "kardolus";
16 repo = "chatgpt-cli";
17 rev = "v${finalAttrs.version}";
18- hash = "sha256-TXdxqPoyt3VUeHVkbB0UjNcCqaf+5Xve95RMQOEagTM=";
19 };
2021 vendorHash = null;
22 # The tests of kardolus/chatgpt-cli require an OpenAI API Key to be present in the environment,
23- # (e.g. https://github.com/kardolus/chatgpt-cli/blob/v1.8.5/test/contract/contract_test.go#L35)
24 # which will not be the case in the pipeline.
25 # Therefore, tests must be skipped.
26 doCheck = false;
···9 # "chatgpt-cli" is taken by another package with the same upsteam name.
10 # To keep "pname" and "package attribute name" identical, the owners name (kardolus) gets prefixed as identifier.
11 pname = "kardolus-chatgpt-cli";
12+ version = "1.8.6";
1314 src = fetchFromGitHub {
15 owner = "kardolus";
16 repo = "chatgpt-cli";
17 rev = "v${finalAttrs.version}";
18+ hash = "sha256-ggakrfeV6guGhBbA45A78oMFQSMqh9+yvJK+cic1JdY=";
19 };
2021 vendorHash = null;
22 # The tests of kardolus/chatgpt-cli require an OpenAI API Key to be present in the environment,
23+ # (e.g. https://github.com/kardolus/chatgpt-cli/blob/v1.8.6/test/contract/contract_test.go#L35)
24 # which will not be the case in the pipeline.
25 # Therefore, tests must be skipped.
26 doCheck = false;
···1519 openssl_3_0 = openssl_3; # Added 2022-06-27
1520 opensycl = lib.warnOnInstantiate "'opensycl' has been renamed to 'adaptivecpp'" adaptivecpp; # Added 2024-12-04
1521 opensyclWithRocm = lib.warnOnInstantiate "'opensyclWithRocm' has been renamed to 'adaptivecppWithRocm'" adaptivecppWithRocm; # Added 2024-12-04
01522 opentofu-ls = lib.warnOnInstantiate "'opentofu-ls' has been renamed to 'tofu-ls'" tofu-ls; # Added 2025-06-10
1523 openvdb_11 = throw "'openvdb_11' has been removed in favor of the latest version'"; # Added 2025-05-03
1524 opera = throw "'opera' has been removed due to lack of maintenance in nixpkgs"; # Added 2025-05-19
···1519 openssl_3_0 = openssl_3; # Added 2022-06-27
1520 opensycl = lib.warnOnInstantiate "'opensycl' has been renamed to 'adaptivecpp'" adaptivecpp; # Added 2024-12-04
1521 opensyclWithRocm = lib.warnOnInstantiate "'opensyclWithRocm' has been renamed to 'adaptivecppWithRocm'" adaptivecppWithRocm; # Added 2024-12-04
1522+ open-timeline-io = lib.warnOnInstantiate "'open-timeline-io' has been renamed to 'opentimelineio'" opentimelineio; # Added 2025-08-10
1523 opentofu-ls = lib.warnOnInstantiate "'opentofu-ls' has been renamed to 'tofu-ls'" tofu-ls; # Added 2025-06-10
1524 openvdb_11 = throw "'openvdb_11' has been removed in favor of the latest version'"; # Added 2025-05-03
1525 opera = throw "'opera' has been removed due to lack of maintenance in nixpkgs"; # Added 2025-05-19