Repository: NixOS/nixpkgs
Pull request #406252: Use cacert in Nextcloud
Author: login: provokateurin
Labels: name: 6.topic: nixos
description: Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS
name: 8.has: module (update)
description: This PR changes an existing module in `nixos/`
name: 10.rebuild-linux: 1-10
description: This PR causes between 1 and 10 packages to rebuild on Linux.
name: 10.rebuild-darwin: 0
description: This PR does not cause any packages to rebuild on Darwin.
Created: 2025-05-11T19:40:02Z | Merged: 2025-05-15T16:50:53Z

<!--
^ Please summarise the changes you have done and explain why they are necessary here ^

For package updates please link to a changelog or describe changes, this helps your fellow maintainers discover breaking updates.
For new packages please briefly describe the package or provide a link to its homepage.
-->

Replaces https://github.com/NixOS/nixpkgs/pull/405873.

I tested this on my homelab test VM and the self-signed certificates are now happily accepted when set through `security.pki.certificateFiles`.
I also want to add a test for this, but don't have the time to do that right now, therefore I want to keep the PR in draft until that is done.

## Things done

<!-- Please check what applies. Note that these are not hard requirements but merely serve as information for reviewers. -->

- Built on platform(s)
  - [x] x86_64-linux
  - [ ] aarch64-linux
  - [ ] x86_64-darwin
  - [ ] aarch64-darwin
- For non-Linux: Is sandboxing enabled in `nix.conf`? (See [Nix manual](https://nixos.org/manual/nix/stable/command-ref/conf-file.html))
  - [ ] `sandbox = relaxed`
  - [ ] `sandbox = true`
- [ ] Tested, as applicable:
  - [NixOS test(s)](https://nixos.org/manual/nixos/unstable/index.html#sec-nixos-tests) (look inside [nixos/tests](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests))
  - and/or [package tests](https://github.com/NixOS/nixpkgs/blob/master/pkgs/README.md#package-tests)
  - or, for functions and "core" functionality, tests in [lib/tests](https://github.com/NixOS/nixpkgs/blob/master/lib/tests) or [pkgs/test](https://github.com/NixOS/nixpkgs/blob/master/pkgs/test)
  - made sure NixOS tests are [linked](https://github.com/NixOS/nixpkgs/blob/master/pkgs/README.md#linking-nixos-module-tests-to-a-package) to the relevant packages
- [ ] Tested compilation of all packages that depend on this change using `nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"`. Note: all changes have to be committed, also see [nixpkgs-review usage](https://github.com/Mic92/nixpkgs-review#usage)
- [ ] Tested basic functionality of all binary files (usually in `./result/bin/`)
- [25.05 Release Notes](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2505.section.md) (or backporting [24.11](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2411.section.md) and [25.05](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2505.section.md) Release notes)
  - [ ] (Package updates) Added a release notes entry if the change is major or breaking
  - [ ] (Module updates) Added a release notes entry if the change is significant
  - [ ] (Module addition) Added a release notes entry if adding a new NixOS module
- [x] Fits [CONTRIBUTING.md](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md).

<!--
To help with the large amounts of pull requests, we would appreciate your
reviews of other pull requests, especially simple package updates. Just leave a
comment describing what you have tested in the relevant package/service.
Reviewing helps to reduce the average time-to-merge for everyone.
Thanks a lot if you do!

List of open PRs: https://github.com/NixOS/nixpkgs/pulls
Reviewing guidelines: https://github.com/NixOS/nixpkgs/blob/master/pkgs/README.md#reviewing-contributions
-->

---

Add a :+1: [reaction] to [pull requests you find important].

[reaction]: https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/
[pull requests you find important]: https://github.com/NixOS/nixpkgs/pulls?q=is%3Aopen+sort%3Areactions-%2B1-desc



Diff:
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index 65845156fc498..783b1937cb655 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -9,6 +9,11 @@ with lib;
 
 let
   cfg = config.services.nextcloud;
+
+  overridePackage = cfg.package.override {
+    inherit (config.security.pki) caBundle;
+  };
+
   fpm = config.services.phpfpm.pools.nextcloud;
 
   jsonFormat = pkgs.formats.json { };
@@ -51,13 +56,13 @@ let
   };
 
   webroot =
-    pkgs.runCommand "${cfg.package.name or "nextcloud"}-with-apps"
+    pkgs.runCommand "${overridePackage.name or "nextcloud"}-with-apps"
       {
         preferLocalBuild = true;
       }
       ''
         mkdir $out
-        ln -sfv "${cfg.package}"/* "$out"
+        ln -sfv "${overridePackage}"/* "$out"
         ${concatStrings (
           mapAttrsToList (
             name: store:
@@ -184,8 +189,8 @@ let
   mysqlLocal = cfg.database.createLocally && cfg.config.dbtype == "mysql";
   pgsqlLocal = cfg.database.createLocally && cfg.config.dbtype == "pgsql";
 
-  nextcloudGreaterOrEqualThan = versionAtLeast cfg.package.version;
-  nextcloudOlderThan = versionOlder cfg.package.version;
+  nextcloudGreaterOrEqualThan = versionAtLeast overridePackage.version;
+  nextcloudOlderThan = versionOlder overridePackage.version;
 
   # https://github.com/nextcloud/documentation/pull/11179
   ocmProviderIsNotAStaticDirAnymore =
@@ -1019,12 +1024,12 @@ in
           If you have an existing installation with a custom table prefix, make sure it is
           set correctly in `config.php` and remove the option from your NixOS config.
         '')
-        ++ (optional (versionOlder cfg.package.version "26") (upgradeWarning 25 "23.05"))
-        ++ (optional (versionOlder cfg.package.version "27") (upgradeWarning 26 "23.11"))
-        ++ (optional (versionOlder cfg.package.version "28") (upgradeWarning 27 "24.05"))
-        ++ (optional (versionOlder cfg.package.version "29") (upgradeWarning 28 "24.11"))
-        ++ (optional (versionOlder cfg.package.version "30") (upgradeWarning 29 "24.11"))
-        ++ (optional (versionOlder cfg.package.version "31") (upgradeWarning 30 "25.05"));
+        ++ (optional (versionOlder overridePackage.version "26") (upgradeWarning 25 "23.05"))
+        ++ (optional (versionOlder overridePackage.version "27") (upgradeWarning 26 "23.11"))
+        ++ (optional (versionOlder overridePackage.version "28") (upgradeWarning 27 "24.05"))
+        ++ (optional (versionOlder overridePackage.version "29") (upgradeWarning 28 "24.11"))
+        ++ (optional (versionOlder overridePackage.version "30") (upgradeWarning 29 "24.11"))
+        ++ (optional (versionOlder overridePackage.version "31") (upgradeWarning 30 "25.05"));
 
       services.nextcloud.package =
         with pkgs;
@@ -1377,6 +1382,8 @@ in
             datadirectory = lib.mkDefault "${datadir}/data";
             trusted_domains = [ cfg.hostName ];
             "upgrade.disable-web" = true;
+            # NixOS already provides its own integrity check and the nix store is read-only, therefore Nextcloud does not need to do its own integrity checks.
+            "integrity.check.disabled" = true;
           })
           (lib.mkIf cfg.configureRedis {
             "memcache.distributed" = ''\OC\Memcache\Redis'';
diff --git a/nixos/tests/nextcloud/with-objectstore.nix b/nixos/tests/nextcloud/with-objectstore.nix
index 802c070b879d5..53800b8238bc2 100644
--- a/nixos/tests/nextcloud/with-objectstore.nix
+++ b/nixos/tests/nextcloud/with-objectstore.nix
@@ -26,11 +26,13 @@ runTest (
 
     nodes = {
       nextcloud =
-        { config, pkgs, ... }:
         {
-          networking.firewall.allowedTCPPorts = [ 9000 ];
-          environment.systemPackages = [ pkgs.minio-client ];
-
+          config,
+          pkgs,
+          nodes,
+          ...
+        }:
+        {
           services.nextcloud.config.dbtype = "sqlite";
 
           services.nextcloud.config.objectstore.s3 = {
@@ -39,13 +41,66 @@ runTest (
             autocreate = true;
             key = accessKey;
             secretFile = "${pkgs.writeText "secretKey" secretKey}";
-            hostname = "nextcloud";
-            useSsl = false;
-            port = 9000;
+            hostname = "acme.test";
+            useSsl = true;
+            port = 443;
             usePathStyle = true;
             region = "us-east-1";
           };
 
+          security.pki.certificates = [
+            (builtins.readFile ../common/acme/server/ca.cert.pem)
+          ];
+
+          environment.systemPackages = [ pkgs.minio-client ];
+
+          # The dummy certs are for acme.test, so we pretend that's the FQDN
+          # of the minio VM.
+          networking.extraHosts = ''
+            ${nodes.minio.networking.primaryIPAddress} acme.test
+          '';
+        };
+
+      client =
+        { nodes, ... }:
+        {
+          security.pki.certificates = [
+            (builtins.readFile ../common/acme/server/ca.cert.pem)
+          ];
+          networking.extraHosts = ''
+            ${nodes.minio.networking.primaryIPAddress} acme.test
+          '';
+        };
+
+      minio =
+        { ... }:
+        {
+          security.pki.certificates = [
+            (builtins.readFile ../common/acme/server/ca.cert.pem)
+          ];
+
+          services.nginx = {
+            enable = true;
+            recommendedProxySettings = true;
+
+            virtualHosts."acme.test" = {
+              onlySSL = true;
+              sslCertificate = ../common/acme/server/acme.test.cert.pem;
+              sslCertificateKey = ../common/acme/server/acme.test.key.pem;
+              locations."/".proxyPass = "http://127.0.0.1:9000";
+            };
+          };
+
+          networking.extraHosts = ''
+            127.0.0.1 acme.test
+          '';
+
+          networking.firewall.allowedTCPPorts = [
+            9000
+            80
+            443
+          ];
+
           services.minio = {
             enable = true;
             listenAddress = "0.0.0.0:9000";
@@ -56,18 +111,22 @@ runTest (
     };
 
     test-helpers.init = ''
-      nextcloud.wait_for_open_port(9000)
+      minio.start()
+      minio.wait_for_open_port(9000)
+      minio.wait_for_unit("nginx.service")
+      minio.wait_for_open_port(443)
     '';
 
     test-helpers.extraTests =
       { nodes, ... }:
       ''
+
         with subtest("File is not on the filesystem"):
             nextcloud.succeed("test ! -e ${nodes.nextcloud.services.nextcloud.home}/data/root/files/test-shared-file")
 
         with subtest("Check if file is in S3"):
             nextcloud.succeed(
-                "mc config host add minio http://localhost:9000 ${accessKey} ${secretKey} --api s3v4"
+                "mc config host add minio https://acme.test ${accessKey} ${secretKey} --api s3v4"
             )
             files = nextcloud.succeed('mc ls minio/nextcloud|sort').strip().split('\n')
 
@@ -100,8 +159,8 @@ runTest (
         with subtest("Test download from S3"):
             client.succeed(
                 "env AWS_ACCESS_KEY_ID=${accessKey} AWS_SECRET_ACCESS_KEY=${secretKey} "
-                + f"${lib.getExe pkgs.awscli2} s3 cp s3://nextcloud/{file} test --endpoint-url http://nextcloud:9000 "
-                + "--region us-east-1"
+                + f"${lib.getExe pkgs.awscli2} s3 cp s3://nextcloud/{file} test --endpoint-url https://acme.test "
+                + "--region us-east-1 --ca-bundle /etc/ssl/certs/ca-bundle.crt"
             )
 
             client.succeed("test hi = $(cat test)")
diff --git a/pkgs/servers/nextcloud/default.nix b/pkgs/servers/nextcloud/default.nix
index 31c253cbb62e1..b9e36faa4446e 100644
--- a/pkgs/servers/nextcloud/default.nix
+++ b/pkgs/servers/nextcloud/default.nix
@@ -3,6 +3,8 @@
   stdenvNoCC,
   fetchurl,
   nixosTests,
+  cacert,
+  caBundle ? "${cacert}/etc/ssl/certs/ca-bundle.crt",
   nextcloud30Packages,
   nextcloud31Packages,
 }:
@@ -32,6 +34,10 @@ let
         inherit packages;
       };
 
+      postPatch = ''
+        cp ${caBundle} resources/config/ca-bundle.crt
+      '';
+
       installPhase = ''
         runHook preInstall
         mkdir -p $out/


Reviews:
user: login: Ma27
body: I have an almost-working test btw ;-) 

---

Paging cacert maintainers @fpletz @lukegb 
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T10:22:33Z
user: login: Ma27
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-15T16:50:39Z

Review comments:
diff_hunk: @@ -32,6 +33,10 @@ let
         inherit packages;
       };
 
+      patchPhase = ''
path: pkgs/servers/nextcloud/default.nix
user: login: Ma27
body: `postPatch`, please.

Overriding `patchPhase` means that `patches = []` is not applied anymore. We don't have any in here, but it's not too uncommon for people to do `nextcloud.overrideAttrs (_: { patches = [ custom-patches ]; })`.
created_at: 2025-05-13T10:05:12Z
author_association: MEMBER
diff_hunk: @@ -111,7 +119,12 @@ in
       # P11-Kit trust source.
       environment.etc."ssl/trust-source".source = "${cacertPackage.p11kit}/etc/ssl/trust-source";
     })
-    { security.pki.caBundle = caBundle; }
+    {
+      security.pki = {
+        inherit cacertPackage;
+        inherit caBundle;
path: nixos/modules/security/ca.nix
user: login: Ma27
body: (nit) you can also do `inherit cacertPackage caBundle;`.
Normally, I wouldn't point out such things, but there's another remark, so a second iteration is necessary anyways.
created_at: 2025-05-13T10:19:39Z
author_association: MEMBER
diff_hunk: @@ -94,6 +94,14 @@ in
         (Read-only) the path to the final bundle of certificate authorities as a single file.
       '';
     };
+
+    security.pki.cacertPackage = lib.mkOption {
+      type = lib.types.package;
+      readOnly = true;
+      description = ''
+        (Read-only) the path to the final package containing the bundle of certificate authorities as a single file.
+      '';
path: nixos/modules/security/ca.nix
user: login: Ma27
body: maybe add a `defaultText` with the expression from above so that it's clear in the manual what this is?
created_at: 2025-05-13T10:21:56Z
author_association: MEMBER

PR comments:
user: login: Ma27
created_at: 2025-05-12T16:01:10Z
body: >  I also want to add a test for this, but don't have the time to do that right now, therefore I want to keep the PR in draft until that is done.

Hmm, maybe it's sufficient to expose the minio (or whatever we use) in the object-store test behind TLS and use the test CA we have in nixos/tests? If this works with verification enabled and the CA added to the system-wide bundle of the Nextcloud server, that's it I think.
author_association: MEMBER
user: login: provokateurin
created_at: 2025-05-13T10:29:03Z
body: > I have an almost-working test

Feel free to push :)

I will do the other adjustments on the weekend or next week.
author_association: MEMBER
user: login: Ma27
created_at: 2025-05-13T10:30:57Z
body: Done!

> I will do the other adjustments on the weekend or next week.

No worries.
We may miss the official branch-off, but IMHO this is perfectly reasonable to backport.
author_association: MEMBER
user: login: provokateurin
created_at: 2025-05-13T11:57:53Z
body: @Ma27 If you don't mind you can also do the changes from the review, I agree with all of them. Maybe we can merge it before the branch-off then :)
author_association: MEMBER
user: login: provokateurin
created_at: 2025-05-15T12:06:41Z
body: @ma27 can you fix the formatting?
author_association: MEMBER
user: login: Ma27
created_at: 2025-05-15T15:49:05Z
body: @provokateurin I just realized that we can directly use the caBundle from the CA module by making this a parameter for the nextcloud package. We also need cacert, but this doesn't even get evaluated when using the module because laziness.

I like this even more because the option feels a little pointless given that the relevant path is already exposed. Wdyt?
author_association: MEMBER
user: login: provokateurin
created_at: 2025-05-15T15:49:57Z
body: Ah this solution is a lot cleaner, but the commit message was not adjusted and still mentions security.pki.cacertPackage.
author_association: MEMBER
user: login: Ma27
created_at: 2025-05-15T16:20:06Z
body: Good catch, fixed!
author_association: MEMBER
user: login: provokateurin
created_at: 2025-05-15T16:22:00Z
body: Cool, looks ready to merge to me!
author_association: MEMBER
user: login: SuperSandro2000
created_at: 2025-05-20T16:43:12Z
body: Someone knows how to use compressDrvWeb now?

The following fails since this PR:

```nix
services.nextcoud.package = pkgs.compressDrvWeb pkgs.nextcloud31 {
  extraFindOperands = ''-not -iregex ".*(\/apps\/.*\/l10n\/).*"'';
};
```

```
       (stack trace truncated; use '--show-trace' to show the full, detailed trace)

       error: attribute 'override' missing
       at /nix/store/aj454c0f7biyfxzpinmw28y90377x9jv-source/nixos/modules/services/web-apps/nextcloud.nix:13:21:
           12|
           13|   overridePackage = cfg.package.override {
             |                     ^
           14|     inherit (config.security.pki) caBundle;
```
author_association: MEMBER