nextcloud: add `nextcloud.nginx.enableFastcgiRequestBuffering` option

Enabling this option fixes (works around) Nextcloud's notorious "0 byte file"
issue. See these upstream issues:

- https://github.com/nextcloud/documentation/issues/9574
- https://github.com/nextcloud/server/issues/7995

This fixes https://github.com/NixOS/nixpkgs/issues/252980

Co-authored-by: Maximilian Bosch <6025220+Ma27@users.noreply.github.com>

Changed files
+41 -1
nixos
modules
services
tests
nextcloud
+10
nixos/modules/services/web-apps/nextcloud.md
···
services.nextcloud.phpOptions."realpath_cache_size" = "0";
```
+
- **Empty Files on chunked uploads**
+
+
Due to a limitation of PHP-FPM, Nextcloud is unable to handle chunked
+
uploads. See upstream issue
+
[nextcloud/server#7995](https://github.com/nextcloud/server/issues/7995)
+
for details.
+
+
A workaround is to disable chunked uploads with
+
{option}`nextcloud.nginx.enableFastcgiRequestBuffering`.
+
## Using an alternative webserver as reverse-proxy (e.g. `httpd`) {#module-services-nextcloud-httpd}
By default, `nginx` is used as reverse-proxy for `nextcloud`.
+18 -1
nixos/modules/services/web-apps/nextcloud.nix
···
directive and header.
'';
};
+
enableFastcgiRequestBuffering = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
Whether to buffer requests against fastcgi requests. This is a workaround
+
for `PUT` requests with the `Transfer-Encoding: chunked` header set and
+
an unspecified `Content-Length`. Without request buffering for these requests,
+
Nextcloud will create files with zero bytes length as described in
+
[nextcloud/server#7995](https://github.com/nextcloud/server/issues/7995).
+
+
::: {.note}
+
Please keep in mind that upstream suggests to not enable this as it might
+
lead to timeouts on large files being uploaded as described in the
+
[administrator manual](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/big_file_upload_configuration.html#nginx).
+
:::
+
'';
+
};
};
cli.memoryLimit = mkOption {
···
fastcgi_param front_controller_active true;
fastcgi_pass unix:${fpm.socket};
fastcgi_intercept_errors on;
-
fastcgi_request_buffering off;
+
fastcgi_request_buffering ${if cfg.nginx.enableFastcgiRequestBuffering then "on" else "off"};
fastcgi_read_timeout ${builtins.toString cfg.fastcgiTimeout}s;
'';
};
+13
nixos/tests/nextcloud/basic.nix
···
startAt = "20:00";
};
phpExtraExtensions = all: [ all.bz2 ];
+
nginx.enableFastcgiRequestBuffering = true;
};
specialisation.withoutMagick.configuration = {
···
nexcloudWithImagick = findInClosure "imagick" nodes.nextcloud.system.build.vm;
nextcloudWithoutImagick = findInClosure "imagick" nodes.nextcloud.specialisation.withoutMagick.configuration.system.build.vm;
in
+
# python
''
with subtest("File is in proper nextcloud home"):
nextcloud.succeed("test -f ${nodes.nextcloud.services.nextcloud.datadir}/data/root/files/test-shared-file")
···
with subtest("Ensure SSE is disabled by default"):
nextcloud.succeed("grep -vE '^HBEGIN:oc_encryption_module' /var/lib/nextcloud-data/data/root/files/test-shared-file")
+
+
with subtest("Create non-empty files with Transfer-Encoding: chunked"):
+
client.succeed(
+
'dd if=/dev/urandom of=testfile.bin bs=1M count=10',
+
'curl --fail -v -X PUT --header "Transfer-Encoding: chunked" --data-binary @testfile.bin "http://nextcloud/remote.php/webdav/testfile.bin" -u ${config.adminuser}:${config.adminpass}',
+
)
+
+
# Verify the local and remote copies of the file are identical.
+
client_hash = client.succeed("nix-hash testfile.bin").strip()
+
nextcloud_hash = nextcloud.succeed("nix-hash /var/lib/nextcloud-data/data/root/files/testfile.bin").strip()
+
t.assertEqual(client_hash, nextcloud_hash)
'';
}
)