From 61fd078e771dca47081992daa3984f8dbbf29404 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 16:43:23 -0500 Subject: [PATCH 1/3] docs: document Nix as a supported install method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nix support landed in freenet-core#5679: `nix run github:freenet/freenet-core` gives a supervised, self-updating peer that uses the same signed release channel and the same crash-loop rollback as every other install method. Two pages: - `/nix/` — the install guide. Leads with the command, states plainly that the peer updates itself, and distinguishes the two flake outputs, because only one of them runs a peer. `packages.freenet` is a build artifact with no supervisor; a peer started from it falls behind and eventually stops working, so the page says that rather than hedging it. - A one-line pointer in `/quickstart/`, after the OS install tabs. A NixOS user who sees only macOS/Linux/Windows concludes Nix is unsupported and builds it themselves, which is how you get an unsupervised peer. A fourth tab would be wrong (Nix runs *on* Linux and macOS) and would clutter the consumer flow, so a pointer rather than a tab. Two things the page is deliberate about: - It tells operators to install from a release TAG, not the default branch. The default branch can carry an unpublished version number, and a peer that starts ahead of every published release will not update until one overtakes it. - The NixOS snippet sets `home` on the service user. The node keeps its auto-update state (probation marker, rollback snapshot, known-bad pin) under the service user's HOME, not under $STATE_DIRECTORY. A user declared without `home` gets /var/empty, which is not writable, and the peer then runs with crash-loop rollback silently off. Detail is linked to docs/nix.md in freenet-core rather than duplicated, so there is one canonical copy to keep current. --- hugo-site/content/nix/_index.md | 71 ++++++++++++++++++++++++++ hugo-site/content/quickstart/_index.md | 2 + 2 files changed, 73 insertions(+) create mode 100644 hugo-site/content/nix/_index.md diff --git a/hugo-site/content/nix/_index.md b/hugo-site/content/nix/_index.md new file mode 100644 index 00000000..1f90546e --- /dev/null +++ b/hugo-site/content/nix/_index.md @@ -0,0 +1,71 @@ +--- +title: "Freenet on Nix" +date: 2026-09-15 +draft: false +--- + +Freenet runs on Nix and NixOS as a supported deployment. A peer installed this way keeps itself up to date exactly like every other install method, using the same signed release channel. + +## Install + +```bash +nix run github:freenet/freenet-core/vX.Y.Z +``` + +Use a real release tag rather than the default branch. The default branch can carry a version number that has not been published yet, and a peer that starts out ahead of every published release will not update until one overtakes it. Any tag from v0.2.136 onward works. + +Arguments are passed through: + +```bash +nix run github:freenet/freenet-core/vX.Y.Z -- --config-dir /srv/freenet +``` + +{{< alert type="warning" >}} **Your peer updates itself.** Freenet is under active development and releases land often, sometimes several times a day. Older versions stop working as the network moves on, so a peer that stops updating stops being useful to the network. Auto-updates are on by default and should be left on. {{< /alert >}} + +## Two outputs, and only one of them runs a peer + +| Output | Runs a peer? | +|---|---| +| `packages.freenet-node`, which is also `packages.default` | **Yes.** The supervised, self-updating node. This is the supported way to run a peer. | +| `packages.freenet` | **No.** The bare compiler output, for `nix develop`, CI and packaging. | + +`packages.freenet` is a build artifact, not a deployment. It has no supervisor, so nothing applies an update or restarts the node afterwards. A peer started that way falls behind and eventually stops working. If you want to run a peer, run `packages.freenet-node`. + +## Why the binary does not live in the Nix store + +A Freenet node updates by replacing its own executable, after checking the new release against a signing key built into the binary. The Nix store is read only, so that cannot happen there. + +Instead, Nix seeds the binary once into a writable state directory, and the node maintains it from that point on. You get the normal Nix build and the normal update path, including signature verification, crash-loop rollback and known-bad version pinning. + +The honest cost: the running binary drifts away from the store path it came from, so `nix run` reports the version it seeded rather than the version now running. That is deliberate. Pinning the binary to the store would mean pinning the peer to whatever release your flake happened to name, which is the outcome this design exists to avoid. + +## NixOS + +```nix +systemd.services.freenet-node = { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.freenet-node}/bin/freenet-node"; + User = "freenet"; + StateDirectory = "freenet"; + Restart = "always"; + RestartSec = 30; + }; +}; + +users.users.freenet = { + isSystemUser = true; + group = "freenet"; + home = "/var/lib/freenet"; + createHome = true; +}; +users.groups.freenet = { }; +``` + +The `home` line is load bearing and easy to leave out. `StateDirectory` is not the only directory that has to be writable. The node keeps its auto-update state, meaning the crash-probation marker, the rollback snapshot and the known-bad version pin, under the service user's home directory. A NixOS user declared without `home` gets `/var/empty`, which is not writable, and the peer then runs with crash-loop rollback silently switched off. It will still update. It just loses the safety net that recovers it from a bad release. + +Keep `Restart = "always"`. If another process is already holding the node's port, the supervisor stands down and lets systemd retry rather than fighting it, and `always` is what brings the peer back once the port frees. + +## Further reading + +Full detail, including the update contract, the exit codes the supervisor honours and what it deliberately does not do, is in [`docs/nix.md`](https://github.com/freenet/freenet-core/blob/main/docs/nix.md) in the freenet-core repository. diff --git a/hugo-site/content/quickstart/_index.md b/hugo-site/content/quickstart/_index.md index 0afb5832..640233ec 100644 --- a/hugo-site/content/quickstart/_index.md +++ b/hugo-site/content/quickstart/_index.md @@ -30,6 +30,8 @@ browser. {{< os-install >}} +Using Nix or NixOS? See the [Nix install guide](/nix/). You get the same self-updating peer. + ## Step 2: Join the room Click below to join the **Freenet Official** room. A small daily limit helps protect the room from spam. From a1bbf4714ae3c12626e666f76b0d202c8c7d01bd Mon Sep 17 00:00:00 2001 From: Ian Clarke Date: Mon, 28 Sep 2026 10:38:58 -0500 Subject: [PATCH 2/3] docs(nix): concrete release tag, and point NixOS users at the flake package The page told users to run tag vX.Y.Z and to reference pkgs.freenet-node without saying where it comes from. Name a real tag, show the flake input wiring via specialArgs (matching the ${freenet-node} name docs/nix.md uses), and link to the canonical unit instead of carrying a second, already-drifted copy of it. Claude-Session: https://claude.ai/code/session_016xwEnj4eizFJUpd1bPwPQa --- hugo-site/content/nix/_index.md | 41 +++++++++++++++------------------ 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/hugo-site/content/nix/_index.md b/hugo-site/content/nix/_index.md index 1f90546e..bf88485b 100644 --- a/hugo-site/content/nix/_index.md +++ b/hugo-site/content/nix/_index.md @@ -9,15 +9,15 @@ Freenet runs on Nix and NixOS as a supported deployment. A peer installed this w ## Install ```bash -nix run github:freenet/freenet-core/vX.Y.Z +nix run github:freenet/freenet-core/v0.2.139 ``` -Use a real release tag rather than the default branch. The default branch can carry a version number that has not been published yet, and a peer that starts out ahead of every published release will not update until one overtakes it. Any tag from v0.2.136 onward works. +Use a release tag rather than the default branch. The default branch can carry a version number that has not been published yet, and a peer that starts out ahead of every published release will not update until one overtakes it. Any tag from v0.2.136 onward works, and it does not need to be the newest one: the peer updates itself to the current release on its first run. Arguments are passed through: ```bash -nix run github:freenet/freenet-core/vX.Y.Z -- --config-dir /srv/freenet +nix run github:freenet/freenet-core/v0.2.139 -- --config-dir /srv/freenet ``` {{< alert type="warning" >}} **Your peer updates itself.** Freenet is under active development and releases land often, sometimes several times a day. Older versions stop working as the network moves on, so a peer that stops updating stops being useful to the network. Auto-updates are on by default and should be left on. {{< /alert >}} @@ -37,34 +37,29 @@ A Freenet node updates by replacing its own executable, after checking the new r Instead, Nix seeds the binary once into a writable state directory, and the node maintains it from that point on. You get the normal Nix build and the normal update path, including signature verification, crash-loop rollback and known-bad version pinning. -The honest cost: the running binary drifts away from the store path it came from, so `nix run` reports the version it seeded rather than the version now running. That is deliberate. Pinning the binary to the store would mean pinning the peer to whatever release your flake happened to name, which is the outcome this design exists to avoid. +The honest cost: the running binary drifts away from the store path it came from, so the store path names the version it seeded rather than the version now running. That is deliberate. Pinning the binary to the store would mean pinning the peer to whatever release your flake happened to name, which is the outcome this design exists to avoid. ## NixOS +Add freenet-core as a flake input and hand its `freenet-node` package to your configuration: + ```nix -systemd.services.freenet-node = { - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = "${pkgs.freenet-node}/bin/freenet-node"; - User = "freenet"; - StateDirectory = "freenet"; - Restart = "always"; - RestartSec = 30; +{ + inputs.freenet.url = "github:freenet/freenet-core/v0.2.139"; + + outputs = { nixpkgs, freenet, ... }: { + nixosConfigurations.myhost = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs.freenet-node = freenet.packages.x86_64-linux.freenet-node; + modules = [ ./configuration.nix ]; # which takes { freenet-node, ... } + }; }; -}; - -users.users.freenet = { - isSystemUser = true; - group = "freenet"; - home = "/var/lib/freenet"; - createHome = true; -}; -users.groups.freenet = { }; +} ``` -The `home` line is load bearing and easy to leave out. `StateDirectory` is not the only directory that has to be writable. The node keeps its auto-update state, meaning the crash-probation marker, the rollback snapshot and the known-bad version pin, under the service user's home directory. A NixOS user declared without `home` gets `/var/empty`, which is not writable, and the peer then runs with crash-loop rollback silently switched off. It will still update. It just loses the safety net that recovers it from a bad release. +Use the package rather than the flake's overlay. The package is built with the Rust toolchain Freenet pins, while the overlay builds with whatever compiler your nixpkgs has, which on a stable channel can be too old. -Keep `Restart = "always"`. If another process is already holding the node's port, the supervisor stands down and lets systemd retry rather than fighting it, and `always` is what brings the peer back once the port frees. +The systemd unit to put in `configuration.nix` is in the [NixOS section of `docs/nix.md`](https://github.com/freenet/freenet-core/blob/main/docs/nix.md#running-it-under-systemd-on-nixos). Copy it whole rather than writing your own. Several of its settings look optional and are not. In particular, the service user needs a writable home directory, because that is where the node keeps its crash-loop rollback state. Without it the peer still updates, but a bad release has nothing to roll it back. ## Further reading From 58e5ec2fb13900a781c4dd28cbce0751a2b5cccd Mon Sep 17 00:00:00 2001 From: Ian Clarke Date: Mon, 28 Sep 2026 10:38:58 -0500 Subject: [PATCH 3/3] docs(nix): declare the nixpkgs input the NixOS snippet uses outputs takes nixpkgs but the example never declared it, so a verbatim copy failed to evaluate. Verified by evaluating the snippet together with the docs/nix.md unit: ExecStart resolves to the flake's freenet-node. Claude-Session: https://claude.ai/code/session_016xwEnj4eizFJUpd1bPwPQa --- hugo-site/content/nix/_index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/hugo-site/content/nix/_index.md b/hugo-site/content/nix/_index.md index bf88485b..9334a3d9 100644 --- a/hugo-site/content/nix/_index.md +++ b/hugo-site/content/nix/_index.md @@ -45,6 +45,7 @@ Add freenet-core as a flake input and hand its `freenet-node` package to your co ```nix { + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; inputs.freenet.url = "github:freenet/freenet-core/v0.2.139"; outputs = { nixpkgs, freenet, ... }: {