在Nextcloud中配置上传4GB或更大容量的文件

undefined

Nextcloud 是一个自由、开源的文件同步和共享软件套件。它允许你将文件储存在个人或专有服务器上,并在多个设备之间同步和共享这些文件。Nextcloud 提供了类似于Dropbox的功能,但更加安全和可自定义。它还支持许多插件和扩展,以满足个人和组织的不同需求。Nextcloud 是一个功能强大的解决方案,有助于保护您的文件和数据,并提高企业的协作效率。

很久以前我创建的 ownCloud,最近换成了 Nextcloud。
虽然换成了新的,但是似乎无论上传多少次,大于4GB的大容量文件都无法成功上传,真是没办法。
于是我研究了一下问题,重新调整了设置,终于能够成功上传超过10GB的文件了,这就是我的经历。

我将列举发生的错误以及相应的解决方法。

前提 (Qian ti)

    • サーバースペック

AWS Lightsail
2 GB RAM
1 vCPU
60 GB SSD

Nextcloudバージョン

23.0.2

公式の docker-compose.yml で環境を作成

https://github.com/nextcloud/docker/tree/master/.examples/docker-compose/with-nginx-proxy/mariadb/fpm
nginx (proxy) + nginx (web) + Nextcloud (php-fpm) + mariaDB + redis の全部入り

S3 をプライマリストレージとして使用

发生的错误和解决方法

以下的设置方法是基于使用docker-compose创建的环境。请在其他环境中自行调整。

将PHP文件大小的上限增加

由于PHP默认配置不允许上传大于512MB的文件,因此需要进行配置更改。
在Docker配置中,存在名为PHP_MEMORY_LIMIT和PHP_UPLOAD_LIMIT的设置,需要添加它们。
您可以根据需要自行设置这些值。

diff --git a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/docker-compose.yml b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/docker-compose.yml
index 33b3d92..d89864d 100644
--- a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/docker-compose.yml
+++ b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/docker-compose.yml
@@ -24,6 +24,16 @@ services:
     environment:
       - MYSQL_HOST=db
       - REDIS_HOST=redis
       - OVERWRITEPROTOCOL=https
       - OBJECTSTORE_S3_HOST=s3.ap-northeast-1.amazonaws.com
       - OBJECTSTORE_S3_BUCKET=hogehoge-drive
       - OBJECTSTORE_S3_KEY=AAAAAAAAAAAAAAAA
       - OBJECTSTORE_S3_SECRET=aaaaaaaaaaaaaaaaaaaaaaaaaa
       - OBJECTSTORE_S3_PORT=443
       - OBJECTSTORE_S3_SSL=true
       - OBJECTSTORE_S3_REGION=ap-northeast-1
+      - PHP_MEMORY_LIMIT=1G
+      - PHP_UPLOAD_LIMIT=5G
     env_file:
       - db.env
     depends_on:

尽管设置 PHP_MEMORY_LIMIT 不影响运行,但是由于我环境中有足够的内存,因此我进行了设置。

增加Nginx的文件大小限制

代理和网络的Nginx配置都需要更改,才能上传大容量文件。
默认设置限制为512MB,因此需要更改相应的配置。

更改代理设置

diff --git a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/proxy/uploadsize.conf b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/proxy/uploadsize.conf
index 7e3906e..eb05553 100644
--- a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/proxy/uploadsize.conf
+++ b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/proxy/uploadsize.conf
@@ -1,2 +1,6 @@
-client_max_body_size 10G;
+client_max_body_size 15G;
 proxy_request_buffering off;

网络设置更改

diff --git a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf
index 8fbc162..6af9b77 100644
--- a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf
+++ b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf
@@ -42,7 +42,7 @@ http {
         #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;

         # set max upload size
-        client_max_body_size 512M;
+        client_max_body_size 15G;
         fastcgi_buffers 64 4K;

         # Enable gzip but do not remove ETag headers

設置各種超時時間

从这里开始是正题。根据之前的设置进行了同步,发现能够上传约3GB左右的文件,但是当文件大小大约达到4GB或以上时,会出现以下的错误。

组装块时出现错误,状态代码504。

组装块时的错误,状态码504。

据说,Nextcloud在上传大容量文件时会将文件分割发送,但似乎在PHP端合并分割文件花费了较长时间,在此期间nginx会因为超时而中断。此外,据说如果PHP执行本身花费了较长时间,也会导致超时并取消PHP的执行。

(参考)
以下是原文链接(需翻墙):
1. https://help.nextcloud.com/t/error-when-assembling-chunks-status-code-504/56751/6
2. https://github.com/nextcloud/server/issues/17992
3. https://github.com/linuxserver/docker-nextcloud/issues/211

为此,需要提高nginx端的超时值上限和PHP的执行时间上限。
需要分别设置proxy和web的nginx端超时值。

超时时间可以根据个人喜好进行设置。这里设定为30分钟。

更改代理设置

diff --git a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/proxy/uploadsize.conf b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/proxy/uploadsize.conf
index 7e3906e..eb05553 100644
--- a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/proxy/uploadsize.conf
+++ b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/proxy/uploadsize.conf
@@ -1,2 +1,6 @@
 client_max_body_size 15G;
 proxy_request_buffering off;
+proxy_connect_timeout 1800;
+proxy_send_timeout 1800;
+proxy_read_timeout 1800;
+send_timeout 1800;

网页的设置更改

diff --git a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf
index 8fbc162..6af9b77 100644
--- a/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf
+++ b/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf
@@ -144,6 +144,11 @@ http {

             fastcgi_intercept_errors on;
             fastcgi_request_buffering off;
+
+            fastcgi_read_timeout 1800;
+            fastcgi_send_timeout 1800;
+            fastcgi_connect_timeout 1800;

更改 PHP 的执行时间

由于无法直接更改PHP的执行时间,因此需要进入docker容器并修改PHP的配置文件。

首先进入docker容器内部。

$ sudo docker exec -it fpm-app-1 sh

在容器中安装编辑器,并打开PHP配置文件。

$ apk add vim
$ vim /usr/local/etc/php/conf.d/nextcloud.ini

打开PHP的配置文件,添加以下行代码。

--- nextcloud.ini
+++ /usr/local/etc/php/conf.d/nextcloud.ini
@@ -1,3 +1,5 @@
 memory_limit=${PHP_MEMORY_LIMIT}
 upload_max_filesize=${PHP_UPLOAD_LIMIT}
 post_max_size=${PHP_UPLOAD_LIMIT}
+max_execution_time=1800
+max_input_time=1800

调整向S3的多部分上传的并行度

改变了超时值并上传后,现在出现了这种错误。

An exception occurred while uploading parts to a multipart upload. The following parts had errors:
- Part 1: Error executing \"UploadPart\" on \"https://s3.eu-central-1.wasabisys.com/example.com/urn%3Aoid%3A6899?partNumber=1&uploadId=0p_vUl_cL8R-z7o7JQacOPTjP3Vhqy_sVxwGv8CRVa39uzWZqBC_IrD0wfP9d0sLVAX_uGkLalq-Fhguy7FgJcHspt9ZeeZ3yzqYEcUbmVhY1ONPX5X57BVpRajusER6\"; AWS HTTP error: Client error: `PUT https://s3.eu-central-1.wasabisys.com/example.com/urn%3Aoid%3A6899?partNumber=1&uploadId=0p_vUl_cL8R-z7o7JQacOPTjP3Vhqy_sVxwGv8CRVa39uzWZqBC_IrD0wfP9d0sLVAX_uGkLalq-Fhguy7FgJcHspt9ZeeZ3yzqYEcUbmVhY1ONPX5X57BVpRajusER6` resulted in a `400 Bad Request` response:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<Error><Code>RequestTimeout</Code><Message>Your socket connection to the server w (truncated...)
 RequestTimeout (client): Your socket connection to the server was not read from or written to within the timeout period, source:  read tcp 130.117.252.13:443->78.46.193.122:35876: i/o timeout - <?xml version=\"1.0\" encoding=\"UTF-8\"?>
<Error><Code>RequestTimeout</Code><Message>Your socket connection to the server was not read from or written to within the timeout period, source:  read tcp 130.117.252.13:443-&gt;78.46.193.122:35876: i/o timeout</Message><RequestId>0800D03C011B289E</RequestId><HostId>4K4Kd98tbwzYAQ9Of04l+YWtRoC4ykRJcznDiTbqFljFzHuqkVVIFAGYqpOTqzaNvYqrHRXFJk6m</HostId></Error>
- Part 2: Error executing ...

好像在向S3进行多部分上传时发生了超时问题。

当查阅有关 PR 的信息时,我了解到在 Nextcloud 中使用的 AWS SDK for PHP 能够通过指定并行度来实现并行多部分上传。然而,如果服务器规格不足,会增加负载并导致上传到 S3 的操作超时。

(参考)在下面链接的GitHub页面中,你可以找到一个关于Nextcloud服务器的拉取请求(Pull Request)编号为24330的讨论和代码更改。

所以,似乎最好不要将并行度设置为默认值5,而应该进一步减少数量。
由于在v23.0.2的Nextcloud中无法更改并行度,所以必须直接修改源代码中的PHP。

再次进入 Docker 容器内。

$ sudo docker exec -it fpm-app-1 sh

当进入容器后,打开相应处理的源代码。

$ vim lib/private/Files/ObjectStore/S3ObjectTrait.php

在执行多部分上传处理时,添加以下并发设置。

--- ./S3ObjectTrait_original.php
+++ lib/private/Files/ObjectStore/S3ObjectTrait.php
@@ -110,11 +110,10 @@
        protected function writeMultiPart(string $urn, StreamInterface $stream, string $mimetype = null): void {
                $uploader = new MultipartUploader($this->getConnection(), $stream, [
                        'bucket' => $this->bucket,
                        'key' => $urn,
                        'part_size' => $this->uploadPartSize,
+                       'concurrency' => 1,
                        'params' => [
                                'ContentType' => $mimetype
                        ],
                ]);

我自己的情况下,如果选择 1,就完全不会出现错误,并且能够成功同步超过10GB的文件。真是太高兴了。

undefined

最后

最初决定转向Nextcloud时,我很高兴地创建了环境,因为官方有docker-compose.yml可用,真是太好了!。但后来发现无法同步大文件,于是我花了几天时间不断尝试和纠结。
由于大文件大小,每次尝试都需要花费很长时间,一度完全失去了兴趣,但好在最终我设法成功同步了超过10GB的文件,真是太好了。

bannerAds