···323323324324- Package `pash` was removed due to being archived upstream. Use `powershell` as an alternative.
325325326326+- The option `services.plausible.releaseCookiePath` has been removed: Plausible does not use any distributed Erlang features, and does not plan to (see [discussion](https://github.com/NixOS/nixpkgs/pull/130297#issuecomment-1805851333)), so NixOS now disables them, and the Erlang cookie becomes unnecessary. You may delete the file that `releaseCookiePath` was set to.
327327+326328- `security.sudo.extraRules` now includes `root`'s default rule, with ordering
327329 priority 400. This is functionally identical for users not specifying rule
328330 order, or relying on `mkBefore` and `mkAfter`, but may impact users calling
+41-11
nixos/modules/services/web-apps/plausible.nix
···11111212 package = mkPackageOptionMD pkgs "plausible" { };
13131414- releaseCookiePath = mkOption {
1515- type = with types; either str path;
1616- description = lib.mdDoc ''
1717- The path to the file with release cookie. (used for remote connection to the running node).
1818- '';
1919- };
2020-2114 adminUser = {
2215 name = mkOption {
2316 default = "admin";
···9285 framework docs](https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Secret.html#content).
9386 '';
9487 };
8888+ listenAddress = mkOption {
8989+ default = "127.0.0.1";
9090+ type = types.str;
9191+ description = lib.mdDoc ''
9292+ The IP address on which the server is listening.
9393+ '';
9494+ };
9595 port = mkOption {
9696 default = 8000;
9797 type = types.port;
···162162 };
163163 };
164164165165+ imports = [
166166+ (mkRemovedOptionModule [ "services" "plausible" "releaseCookiePath" ] "Plausible uses no distributed Erlang features, so this option is no longer necessary and was removed")
167167+ ];
168168+165169 config = mkIf cfg.enable {
166170 assertions = [
167171 { assertion = cfg.adminUser.activate -> cfg.database.postgres.setup;
···179183 services.clickhouse = mkIf cfg.database.clickhouse.setup {
180184 enable = true;
181185 };
182182-183183- services.epmd.enable = true;
184186185187 environment.systemPackages = [ cfg.package ];
186188···209211 # Configuration options from
210212 # https://plausible.io/docs/self-hosting-configuration
211213 PORT = toString cfg.server.port;
214214+ LISTEN_IP = cfg.server.listenAddress;
215215+216216+ # Note [plausible-needs-no-erlang-distributed-features]:
217217+ # Plausible does not use, and does not plan to use, any of
218218+ # Erlang's distributed features, see:
219219+ # https://github.com/plausible/analytics/pull/1190#issuecomment-1018820934
220220+ # Thus, disable distribution for improved simplicity and security:
221221+ #
222222+ # When distribution is enabled,
223223+ # Elixir spwans the Erlang VM, which will listen by default on all
224224+ # interfaces for messages between Erlang nodes (capable of
225225+ # remote code execution); it can be protected by a cookie; see
226226+ # https://erlang.org/doc/reference_manual/distributed.html#security).
227227+ #
228228+ # It would be possible to restrict the interface to one of our choice
229229+ # (e.g. localhost or a VPN IP) similar to how we do it with `listenAddress`
230230+ # for the Plausible web server; if distribution is ever needed in the future,
231231+ # https://github.com/NixOS/nixpkgs/pull/130297 shows how to do it.
232232+ #
233233+ # But since Plausible does not use this feature in any way,
234234+ # we just disable it.
235235+ RELEASE_DISTRIBUTION = "none";
236236+ # Additional safeguard, in case `RELEASE_DISTRIBUTION=none` ever
237237+ # stops disabling the start of EPMD.
238238+ ERL_EPMD_ADDRESS = "127.0.0.1";
239239+212240 DISABLE_REGISTRATION = if isBool cfg.server.disableRegistration then boolToString cfg.server.disableRegistration else cfg.server.disableRegistration;
213241214242 RELEASE_TMP = "/var/lib/plausible/tmp";
···238266 path = [ cfg.package ]
239267 ++ optional cfg.database.postgres.setup config.services.postgresql.package;
240268 script = ''
241241- export RELEASE_COOKIE="$(< $CREDENTIALS_DIRECTORY/RELEASE_COOKIE )"
269269+ # Elixir does not start up if `RELEASE_COOKIE` is not set,
270270+ # even though we set `RELEASE_DISTRIBUTION=none` so the cookie should be unused.
271271+ # Thus, make a random one, which should then be ignored.
272272+ export RELEASE_COOKIE=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 20)
242273 export ADMIN_USER_PWD="$(< $CREDENTIALS_DIRECTORY/ADMIN_USER_PWD )"
243274 export SECRET_KEY_BASE="$(< $CREDENTIALS_DIRECTORY/SECRET_KEY_BASE )"
244275···265296 LoadCredential = [
266297 "ADMIN_USER_PWD:${cfg.adminUser.passwordFile}"
267298 "SECRET_KEY_BASE:${cfg.server.secretKeybaseFile}"
268268- "RELEASE_COOKIE:${cfg.releaseCookiePath}"
269299 ] ++ lib.optionals (cfg.mail.smtp.passwordFile != null) [ "SMTP_USER_PWD:${cfg.mail.smtp.passwordFile}"];
270300 };
271301 };
+4-3
nixos/tests/plausible.nix
···88 virtualisation.memorySize = 4096;
99 services.plausible = {
1010 enable = true;
1111- releaseCookiePath = "${pkgs.runCommand "cookie" { } ''
1212- ${pkgs.openssl}/bin/openssl rand -base64 64 >"$out"
1313- ''}";
1411 adminUser = {
1512 email = "admin@example.org";
1613 passwordFile = "${pkgs.writeText "pwd" "foobar"}";
···2724 start_all()
2825 machine.wait_for_unit("plausible.service")
2926 machine.wait_for_open_port(8000)
2727+2828+ # Ensure that the software does not make not make the machine
2929+ # listen on any public interfaces by default.
3030+ machine.fail("ss -tlpn 'src = 0.0.0.0 or src = [::]' | grep LISTEN")
30313132 machine.succeed("curl -f localhost:8000 >&2")
3233