nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix

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>

+41 -1
+10
nixos/modules/services/web-apps/nextcloud.md
··· 211 211 services.nextcloud.phpOptions."realpath_cache_size" = "0"; 212 212 ``` 213 213 214 + - **Empty Files on chunked uploads** 215 + 216 + Due to a limitation of PHP-FPM, Nextcloud is unable to handle chunked 217 + uploads. See upstream issue 218 + [nextcloud/server#7995](https://github.com/nextcloud/server/issues/7995) 219 + for details. 220 + 221 + A workaround is to disable chunked uploads with 222 + {option}`nextcloud.nginx.enableFastcgiRequestBuffering`. 223 + 214 224 ## Using an alternative webserver as reverse-proxy (e.g. `httpd`) {#module-services-nextcloud-httpd} 215 225 216 226 By default, `nginx` is used as reverse-proxy for `nextcloud`.
+18 -1
nixos/modules/services/web-apps/nextcloud.nix
··· 986 986 directive and header. 987 987 ''; 988 988 }; 989 + enableFastcgiRequestBuffering = mkOption { 990 + type = types.bool; 991 + default = false; 992 + description = '' 993 + Whether to buffer requests against fastcgi requests. This is a workaround 994 + for `PUT` requests with the `Transfer-Encoding: chunked` header set and 995 + an unspecified `Content-Length`. Without request buffering for these requests, 996 + Nextcloud will create files with zero bytes length as described in 997 + [nextcloud/server#7995](https://github.com/nextcloud/server/issues/7995). 998 + 999 + ::: {.note} 1000 + Please keep in mind that upstream suggests to not enable this as it might 1001 + lead to timeouts on large files being uploaded as described in the 1002 + [administrator manual](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/big_file_upload_configuration.html#nginx). 1003 + ::: 1004 + ''; 1005 + }; 989 1006 }; 990 1007 991 1008 cli.memoryLimit = mkOption { ··· 1493 1476 fastcgi_param front_controller_active true; 1494 1477 fastcgi_pass unix:${fpm.socket}; 1495 1478 fastcgi_intercept_errors on; 1496 - fastcgi_request_buffering off; 1479 + fastcgi_request_buffering ${if cfg.nginx.enableFastcgiRequestBuffering then "on" else "off"}; 1497 1480 fastcgi_read_timeout ${builtins.toString cfg.fastcgiTimeout}s; 1498 1481 ''; 1499 1482 };
+13
nixos/tests/nextcloud/basic.nix
··· 62 62 startAt = "20:00"; 63 63 }; 64 64 phpExtraExtensions = all: [ all.bz2 ]; 65 + nginx.enableFastcgiRequestBuffering = true; 65 66 }; 66 67 67 68 specialisation.withoutMagick.configuration = { ··· 91 90 nexcloudWithImagick = findInClosure "imagick" nodes.nextcloud.system.build.vm; 92 91 nextcloudWithoutImagick = findInClosure "imagick" nodes.nextcloud.specialisation.withoutMagick.configuration.system.build.vm; 93 92 in 93 + # python 94 94 '' 95 95 with subtest("File is in proper nextcloud home"): 96 96 nextcloud.succeed("test -f ${nodes.nextcloud.services.nextcloud.datadir}/data/root/files/test-shared-file") ··· 105 103 106 104 with subtest("Ensure SSE is disabled by default"): 107 105 nextcloud.succeed("grep -vE '^HBEGIN:oc_encryption_module' /var/lib/nextcloud-data/data/root/files/test-shared-file") 106 + 107 + with subtest("Create non-empty files with Transfer-Encoding: chunked"): 108 + client.succeed( 109 + 'dd if=/dev/urandom of=testfile.bin bs=1M count=10', 110 + '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}', 111 + ) 112 + 113 + # Verify the local and remote copies of the file are identical. 114 + client_hash = client.succeed("nix-hash testfile.bin").strip() 115 + nextcloud_hash = nextcloud.succeed("nix-hash /var/lib/nextcloud-data/data/root/files/testfile.bin").strip() 116 + t.assertEqual(client_hash, nextcloud_hash) 108 117 ''; 109 118 } 110 119 )