Upload speed issues: Bandwidth idles waiting for 200 response & transatlantic upload capped at ~5 MB/s

The Basics

We are a yet small but growing maritime protection NGO. We had a very bad situation with Google as they shut down our account for 11 days without any given reason or warning. Since then we are trying to give Nextcloud a serious try. I love Nextcloud and I really want to get this running!

  • Nextcloud Server version: Nextcloud Hub 26 Winter (33.0.5)

  • Operating system and version: Linux 6.8.0-117-generic aarch64, ARM, Ubuntu 24.04

  • Web server and version: AIO

  • Reverse proxy and version: AIO (caddy)

  • PHP version: AIO

  • Is this the first time you’ve seen this error? Yes

  • When did this problem seem to first start? Present since initial setup of this instance

  • Installation method: AIO (Nextcloud AIO v13.2.1)

  • Are you using Cloudflare, mod_security, or similar? None.

  • Hosting: Hetzner VPS cax31 (ARM, 8vCPU, 16GB), Helsinki.

  • Primary storage backend: Object storage, Hetzner S3 in same location as VPS.

Summary of the issue you are facing

I’m uploading test files (1GB, 5GB) from an AWS Windows client in the USA (Oregon) to a Nextcloud AIO instance in Europe (Helsinki), RTT ~185 ms, with no packet loss. I’m hitting two related problems which cause a drastically reduces upload speed:

Issue 1: Bandwidth idles between chunk batches.

The web UI uploads in batches of 5 parallel chunks (100 MB each). In the browser Developer Tools Network tab, all 5 chunks start together and finish together, then there’s a short wait (~8 seconds) for the 200 responses from Nextcloud before the next batch begins. For some reason, it takes Nextcloud quite long (8 seconds) to respond with 200. During 8 seconds the bandwidth goes to idle. Staggering the chunk starts would be amazing to keep bandwidth fully utilized. When uploading 5 GB, the chunks get out of sync eventually and causes the next chunks to start at individual times, which reduces or sometimes eliminates the 8 seconds entirely.

Issue 2: Transatlantic upload speed is capped at 5 MB/s.

Uploads tops at roughly 5 MB/s from the client in Oregon. A AWS client in Stockholm is uploading at 25 MB/s. Sure, long distance causes latency. But concurrent upload streams should eventually almost reach the same speed as closer clients, right?

Steps to replicate it (hint: details matter!)

  1. Server in EU, client in USA (~185 ms RTT, no loss).

  2. Upload a large file (≥1 GB) via the web UI.

  3. Open browser DevTools → Network tab.

  4. Observe: chunks upload in batches of 5, start and finish in lockstep.

  5. Aggregate throughput tops out around ~50 Mbit/s. Measured in Task Manager or htop/btop on server side. Showing 5 MB/s in web-ui.

What I’ve already tested / ruled out:

  • Packet loss: none (ping -n 100, 0% loss).

  • Server TCP: BBR already enabled.

  • Browsers: Firefox is ~half the speed of Edge on the same client (both HTTP/2 / h2). Probably a different issue, won’t go into details here.

  • Other clients
    rclone:
    Tested --transfers 16 throughput stayed poor. Didnt optimize further.
    Nextcloud Windows client: Same result as in the web-ui. Bandwidth drop, 5 MB/s.
    AI script: Tested using curl and a staggering chunk start in a script. It reached 50 MB/s from the same client. Assembling the file takes very long too, but probably another issue.

  • files max_chunk_size change via occ had no effect on web UI chunk size (stayed 100 MB).

  • Speed test with iperf3: 87 MB/s upload to Nextcloud from Oregon (long distance). 500 MB/s download to Oregon client. The general connection between them does not seem to be the problem.

  • Tested from a closer location as well. Which was much faster, but still had small bandwidth idle gaps of 5-8 seconds between chunk batches.

  • Just as a comparison: Dropbox uploads are running with 75 MB/s continuously. I know, it’s not fair to compare, but my users are comparing it this way.

  • I also tested with a fresh Nextcloud AiO installation with local disk as primary storage. While it did reduce the bandwidth idle (issue 1) a lot, it still maxed out at 5 MB/s (issue 2) from the remote (Oregon) location.

Key questions

  1. Is there a way to stagger chunk starts so the pipeline doesn’t site in idle while waiting for 200? Could staggering be an interesting feature to implement?

  2. What other ways could be used to increase the general upload speed?

  3. Why are web-ui and Windows application apparently maxing out at 5 MB/s on long distances?

  4. What could be a (temporary) solution?

    1. Are there any settings, bottlenecks, or bugs that can fix the issue?

    2. Use local hard drive instead of S3? Going to be tricky, as we need 2 TB+.

    3. Move to bare metal? Expensive, but possible, if this solves the issue.

    4. Move server to US, since most heavy data will be done from there. But then other people will have the issue. How do other bigger organizations solve this?

      1. One Nextcloud system per continent and have them federated?

      2. CDN?

Log entries

Nextcloud

Some dirty table messages in there.

Just some example messages. The entire log is too big. Please let me know if you need it anyways.

Summary
{"reqId":"mcBZ7XBxECSYHLsd4AMS","level":0,"time":"2026-06-14T22:39:18+00:00","remoteAddr":"52.10.22.27","user":"--","app":"core","method":"PUT","url":"/remote.php/dav/uploads/testupload/web-file-upload-af729bceee77a05b/3","scriptName":"/remote.php","message":"Slow session_start detected","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"core","timeSpent":"0.11850905418395996"}}

{"reqId":"HMItUtGSwjRhhlXQlgH6","level":0,"time":"2026-06-14T22:39:18+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"serverDI","method":"PUT","url":"/remote.php/dav/uploads/testupload/web-file-upload-af729bceee77a05b/5","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"kbJGqIPxHRlZq48E8Wfe","level":1,"time":"2026-06-14T22:41:04+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"no app in context","method":"PUT","url":"/remote.php/dav/uploads/testupload/web-file-upload-af729bceee77a05b/6","scriptName":"/remote.php","message":"The app config key dav/enableCalendarFederation is not defined in the config lexicon","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":[]}

{"reqId":"o3fyfnelLxwyhNeQZzM2","level":0,"time":"2026-06-14T22:41:04+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"no app in context","method":"PUT","url":"/remote.php/dav/uploads/testupload/web-file-upload-af729bceee77a05b/4","scriptName":"/remote.php","message":"dirty table reads: SELECT `path` FROM `*PREFIX*filecache` WHERE (`storage` = :dcValue1) AND (`fileid` = :dcValue2)","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","exception":{"Exception":"Exception","Message":"dirty table reads: SELECT `path` FROM `*PREFIX*filecache` WHERE (`storage` = :dcValue1) AND (`fileid` = :dcValue2)","Code":0,"Trace":[{"file":"/var/www/html/lib/private/DB/ConnectionAdapter.php","line":50,"function":"executeQuery","class":"OC\\DB\\Connection","type":"->","args":["SELECT `path` FROM `*PREFIX*filecache` WHERE (`storage` = :dcValue1) AND (`fileid` = :dcValue2)",{"dcValue1":97,"dcValue2":"*** sensitive parameters replaced ***"},{"dcValue1":1,"dcValue2":1}]},{"file":"/var/www/html/lib/private/DB/QueryBuilder/QueryBuilder.php","line":268,"function":"executeQuery","class":"OC\\DB\\ConnectionAdapter","type":"->","args":["SELECT `path` FROM `*PREFIX*filecache` WHERE (`storage` = :dcValue1) AND (`fileid` = :dcValue2)",{"dcValue1":97,"dcValue2":"*** sensitive parameters replaced ***"},{"dcValue1":1,"dcValue2":1}]},{"file":"/var/www/html/lib/private/DB/QueryBuilder/ExtendedQueryBuilder.php","line":270,"function":"executeQuery","class":"OC\\DB\\QueryBuilder\\QueryBuilder","type":"->","args":[{"__class__":"OC\\DB\\ConnectionAdapter"}]},{"file":"/var/www/html/lib/private/Files/Cache/Cache.php","line":1134,"function":"executeQuery","class":"OC\\DB\\QueryBuilder\\ExtendedQueryBuilder","type":"->","args":[]},{"file":"/var/www/html/lib/private/Files/Cache/Cache.php","line":426,"function":"getPathById","class":"OC\\Files\\Cache\\Cache","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/html/apps/dav/lib/Upload/ChunkingV2Plugin.php","line":179,"function":"update","class":"OC\\Files\\Cache\\Cache","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php","line":89,"function":"beforePut","class":"OCA\\DAV\\Upload\\ChunkingV2Plugin","type":"->","args":[{"__class__":"Sabre\\HTTP\\Request"},{"__class__":"Sabre\\HTTP\\Response"}]},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":456,"function":"emit","class":"Sabre\\DAV\\Server","type":"->","args":["beforeMethod:PUT",[{"__class__":"Sabre\\HTTP\\Request"},{"__class__":"Sabre\\HTTP\\Response"}]]},{"file":"/var/www/html/apps/dav/lib/Connector/Sabre/Server.php","line":212,"function":"invokeMethod","class":"Sabre\\DAV\\Server","type":"->","args":[{"__class__":"Sabre\\HTTP\\Request"},{"__class__":"Sabre\\HTTP\\Response"}]},{"file":"/var/www/html/apps/dav/lib/Server.php","line":428,"function":"start","class":"OCA\\DAV\\Connector\\Sabre\\Server","type":"->","args":[]},{"file":"/var/www/html/apps/dav/appinfo/v2/remote.php","line":25,"function":"exec","class":"OCA\\DAV\\Server","type":"->","args":[]},{"file":"/var/www/html/remote.php","line":151,"args":["/var/www/html/apps/dav/appinfo/v2/remote.php"],"function":"require_once"}],"File":"/var/www/html/lib/private/DB/Connection.php","Line":407,"message":"dirty table reads: SELECT `path` FROM `*PREFIX*filecache` WHERE (`storage` = :dcValue1) AND (`fileid` = :dcValue2)","tables":"[\"oc_filecache\"]","reads":"[\"oc_filecache\"]","exception":"{\"class\":\"Exception\",\"message\":\"dirty table reads: SELECT `path` FROM `*PREFIX*filecache` WHERE (`storage` = :dcValue1) AND (`fileid` = :dcValue2)\",\"code\":0,\"file\":\"/var/www/html/lib/private/DB/Connection.php:407\",\"trace\":\"#0 /var/www/html/lib/private/DB/ConnectionAdapter.php(50): OC\\DB\\Connection->executeQuery('SELECT `path` F...', Array, Array)\\n#1 /var/www/html/lib/private/DB/QueryBuilder/QueryBuilder.php(268): OC\\DB\\ConnectionAdapter->executeQuery('SELECT `path` F...', Array, Array)\\n#2 /var/www/html/lib/private/DB/QueryBuilder/ExtendedQueryBuilder.php(270): OC\\DB\\QueryBuilder\\QueryBuilder->executeQuery(Object(OC\\DB\\ConnectionAdapter))\\n#3 /var/www/html/lib/private/Files/Cache/Cache.php(1134): OC\\DB\\QueryBuilder\\ExtendedQueryBuilder->executeQuery()\\n#4 /var/www/html/lib/private/Files/Cache/Cache.php(426): OC\\Files\\Cache\\Cache->getPathById(457616)\\n#5 /var/www/html/apps/dav/lib/Upload/ChunkingV2Plugin.php(179): OC\\Files\\Cache\\Cache->update(457616, Array)\\n#6 /var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php(89): OCA\\DAV\\Upload\\ChunkingV2Plugin->beforePut(Object(Sabre\\HTTP\\Request), Object(Sabre\\HTTP\\Response))\\n#7 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(456): Sabre\\DAV\\Server->emit('beforeMethod:PU...', Array)\\n#8 /var/www/html/apps/dav/lib/Connector/Sabre/Server.php(212): Sabre\\DAV\\Server->invokeMethod(Object(Sabre\\HTTP\\Request), Object(Sabre\\HTTP\\Response))\\n#9 /var/www/html/apps/dav/lib/Server.php(428): OCA\\DAV\\Connector\\Sabre\\Server->start()\\n#10 /var/www/html/apps/dav/appinfo/v2/remote.php(25): OCA\\DAV\\Server->exec()\\n#11 /var/www/html/remote.php(151): require_once('/var/www/html/a...')\\n#12 {main}\"}","CustomMessage":"dirty table reads: SELECT `path` FROM `*PREFIX*filecache` WHERE (`storage` = :dcValue1) AND (`fileid` = :dcValue2)"}}

{"reqId":"o7RAY6eYOKEpiYE3TgSb","level":0,"time":"2026-06-14T22:41:05+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"serverDI","method":"PUT","url":"/remote.php/dav/uploads/testupload/web-file-upload-af729bceee77a05b/7","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"o7RAY6eYOKEpiYE3TgSb","level":1,"time":"2026-06-14T22:41:05+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"no app in context","method":"PUT","url":"/remote.php/dav/uploads/testupload/web-file-upload-af729bceee77a05b/7","scriptName":"/remote.php","message":"The app config key dav/enableCalendarFederation is not defined in the config lexicon","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":[]}

{"reqId":"wESHmyqSVsAHfHxQZFys","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"--","app":"serverDI","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"HToI2UKuk1eqLw5I7h3f","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"--","app":"serverDI","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"HToI2UKuk1eqLw5I7h3f","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"--","app":"serverDI","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"wESHmyqSVsAHfHxQZFys","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"--","app":"serverDI","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"wESHmyqSVsAHfHxQZFys","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"--","app":"serverDI","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"HToI2UKuk1eqLw5I7h3f","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"serverDI","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"HToI2UKuk1eqLw5I7h3f","level":1,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"no app in context","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The app config key dav/enableCalendarFederation is not defined in the config lexicon","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":[]}

{"reqId":"HToI2UKuk1eqLw5I7h3f","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"serverDI","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"HToI2UKuk1eqLw5I7h3f","level":1,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"no app in context","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The app config key dav/sendInvitations is not defined in the config lexicon","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":[]}

{"reqId":"wESHmyqSVsAHfHxQZFys","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"--","app":"core","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"Slow session_start detected","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"core","timeSpent":"0.10271620750427246"}}

{"reqId":"wESHmyqSVsAHfHxQZFys","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"serverDI","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"wESHmyqSVsAHfHxQZFys","level":1,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"no app in context","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The app config key dav/enableCalendarFederation is not defined in the config lexicon","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":[]}

{"reqId":"wESHmyqSVsAHfHxQZFys","level":0,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"serverDI","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The requested alias \"OCP\\IServerContainer\" is deprecated. Please request \"Psr\\Container\\ContainerInterface\" directly. This alias will be removed in a future Nextcloud version.","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":{"app":"serverDI"}}

{"reqId":"wESHmyqSVsAHfHxQZFys","level":1,"time":"2026-06-14T22:43:07+00:00","remoteAddr":"52.10.22.27","user":"testupload","app":"no app in context","method":"PROPFIND","url":"/remote.php/dav/files/testupload/","scriptName":"/remote.php","message":"The app config key dav/sendInvitations is not defined in the config lexicon","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0","version":"33.0.5.1","data":[]}

Web Browser (Console)

Summary
index.mjs:41 [INFO] activity: Activity API registered Object

index.mjs:41 [INFO] files: Initializing unified search plugin: folder search from files app Object

index.mjs:47 [ERROR] viewer: Could not register handler Object

log @ index.mjs:47

index.mjs:41 [INFO] viewer: 7 viewer handlers registered Object

index.mjs:41 [INFO] core: session heartbeat polling started Object

index.mjs:44 [WARN] @nextcloud/vue: You need to fill either the text or the ariaLabel props in the button component. Object

log @ index.mjs:44

index.mjs:44 [WARN] @nextcloud/vue: You need to fill either the text or the ariaLabel props in the button component. Object

log @ index.mjs:44

index.mjs:41 [INFO] comments: Comments plugin registered for Activity sidebar action Object

files:1 [Intervention] Images loaded lazily and replaced with placeholders. Load events are deferred. See https://go.microsoft.com/fwlink/?linkid=2048113

NotificationsApp.vue:466 Notifications permissions not yet requested

FilesList.vue:386 [ERROR] files: Error while fetching content {app: 'files', uid: 'testupload', level: 0, error: AbortError: signal is aborted without reason

at o.fetchContent (https://*******/dist/fil\Uffffffff}app: "files"error: AbortError: signal is aborted without reason

at o.fetchContent (https://*******/dist/files-main.js?v=5fed912a-3:1:131282)

at o.onUpload (https://*******/dist/files-main.js?v=5fed912a-3:1:132796)

at sn (https://*******/dist/core-common.js?v=5fed912a-3:1:2366540)

at o.n (https://*******/dist/core-common.js?v=5fed912a-3:1:2359291)

at sn (https://*******/dist/core-common.js?v=5fed912a-3:1:2366540)

at o.$emit (https://*******/dist/core-common.js?v=5fed912a-3:1:2387806)

at o.onUploadCompletion (https://*******/dist/files-main.js?v=5fed912a-3:1:634248)

at $._notifyAll (https://*******/dist/files-main.js?v=5fed912a-3:1:620233)

at https://*******/dist/files-main.js?v=5fed912a-3:1:620992level: 0uid: "testupload"[[Prototype]]: Objectconstructor: \Uffffffff Object()hasOwnProperty: \Uffffffff hasOwnProperty()isPrototypeOf: \Uffffffff isPrototypeOf()propertyIsEnumerable: \Uffffffff propertyIsEnumerable()toLocaleString: \Uffffffff toLocaleString()toString: \Uffffffff toString()valueOf: \Uffffffff valueOf()__defineGetter__: \Uffffffff __defineGetter__()__defineSetter__: \Uffffffff __defineSetter__()__lookupGetter__: \Uffffffff __lookupGetter__()__lookupSetter__: \Uffffffff __lookupSetter__()__proto__: (...)get __proto__: \Uffffffff __proto__()set __proto__: \Uffffffff __proto__()

log @ index.mjs:47

error @ index.mjs:65

fetchContent @ FilesList.vue:386

await in fetchContent

onUpload @ FilesList.vue:406

invokeWithErrorHandling @ vue.runtime.esm.js:3033

invoker @ vue.runtime.esm.js:1832

invokeWithErrorHandling @ vue.runtime.esm.js:3033

(anonymous) @ vue.runtime.esm.js:3732

onUploadCompletion @ index-DPkUyJ8g.mjs:1535

_notifyAll @ index-DPkUyJ8g.mjs:669

(anonymous) @ index-DPkUyJ8g.mjs:941

await in (anonymous)

(anonymous) @ index.js:382

_tryToStartAnother @ index.js:253

_next @ index.js:153

(anonymous) @ index.js:415

XMLHttpRequest.send

(anonymous) @ xhr.js:198

(anonymous) @ xhr.js:15

(anonymous) @ dispatchRequest.js:51

Promise.then

_request @ Axios.js:163

request @ Axios.js:40

(anonymous) @ bind.js:12

uploadData @ index-DPkUyJ8g.mjs:65

await in uploadData

(anonymous) @ index-DPkUyJ8g.mjs:864

(anonymous) @ index.js:382

_tryToStartAnother @ index.js:253

_next @ index.js:153

(anonymous) @ index.js:415

XMLHttpRequest.send

(anonymous) @ xhr.js:198

(anonymous) @ xhr.js:15

(anonymous) @ dispatchRequest.js:51

Promise.then

_request @ Axios.js:163

request @ Axios.js:40

(anonymous) @ bind.js:12

uploadData @ index-DPkUyJ8g.mjs:65

await in uploadData

(anonymous) @ index-DPkUyJ8g.mjs:864

(anonymous) @ index.js:382

_tryToStartAnother @ index.js:253

(anonymous) @ index.js:449

add @ index.js:353

(anonymous) @ index-DPkUyJ8g.mjs:907

await in (anonymous)

(anonymous) @ index.js:68

constructor @ index.js:34

upload @ index-DPkUyJ8g.mjs:842

(anonymous) @ index-DPkUyJ8g.mjs:816

await in (anonymous)

(anonymous) @ index.js:68

constructor @ index.js:34

uploadDirectory @ index-DPkUyJ8g.mjs:787

(anonymous) @ index-DPkUyJ8g.mjs:720

await in (anonymous)

(anonymous) @ index.js:68

constructor @ index.js:34

batchUpload @ index-DPkUyJ8g.mjs:710

onPick @ index-DPkUyJ8g.mjs:1503

invokeWithErrorHandling @ vue.runtime.esm.js:3033

invoker @ vue.runtime.esm.js:1832

(anonymous) @ vue.runtime.esm.js:7500

[NEW] Explain Console errors by using Copilot in Edge: click to explain an error. Learn moreDon't show again

FilesList.vue:386 [ERROR] files: Error while fetching content {app: 'files', uid: 'testupload', level: 0, error: AbortError: signal is aborted without reason

at o.fetchContent (https://*******/dist/fil\Uffffffff}app: "files"error: AbortError: signal is aborted without reason

at o.fetchContent (https://*******/dist/files-main.js?v=5fed912a-3:1:131282)

at o.onUpload (https://*******/dist/files-main.js?v=5fed912a-3:1:132796)

at sn (https://*******/dist/core-common.js?v=5fed912a-3:1:2366540)

at o.n (https://*******/dist/core-common.js?v=5fed912a-3:1:2359291)

at sn (https://*******/dist/core-common.js?v=5fed912a-3:1:2366540)

at o.$emit (https://*******/dist/core-common.js?v=5fed912a-3:1:2387806)

at o.onUploadCompletion (https://*******/dist/files-main.js?v=5fed912a-3:1:634248)

at $._notifyAll (https://*******/dist/files-main.js?v=5fed912a-3:1:620233)

at https://*******/dist/files-main.js?v=5fed912a-3:1:620992level: 0uid: "testupload"[[Prototype]]: Object

log @ index.mjs:47

error @ index.mjs:65

fetchContent @ FilesList.vue:386

await in fetchContent

onUpload @ FilesList.vue:406

invokeWithErrorHandling @ vue.runtime.esm.js:3033

invoker @ vue.runtime.esm.js:1832

invokeWithErrorHandling @ vue.runtime.esm.js:3033

(anonymous) @ vue.runtime.esm.js:3732

onUploadCompletion @ index-DPkUyJ8g.mjs:1535

_notifyAll @ index-DPkUyJ8g.mjs:669

(anonymous) @ index-DPkUyJ8g.mjs:941

await in (anonymous)

(anonymous) @ index.js:382

_tryToStartAnother @ index.js:253

_next @ index.js:153

(anonymous) @ index.js:415

XMLHttpRequest.send

(anonymous) @ xhr.js:198

(anonymous) @ xhr.js:15

(anonymous) @ dispatchRequest.js:51

Promise.then

_request @ Axios.js:163

request @ Axios.js:40

(anonymous) @ bind.js:12

uploadData @ index-DPkUyJ8g.mjs:65

await in uploadData

(anonymous) @ index-DPkUyJ8g.mjs:864

(anonymous) @ index.js:382

_tryToStartAnother @ index.js:253

_next @ index.js:153

(anonymous) @ index.js:415

XMLHttpRequest.send

(anonymous) @ xhr.js:198

(anonymous) @ xhr.js:15

(anonymous) @ dispatchRequest.js:51

Promise.then

_request @ Axios.js:163

request @ Axios.js:40

(anonymous) @ bind.js:12

uploadData @ index-DPkUyJ8g.mjs:65

await in uploadData

(anonymous) @ index-DPkUyJ8g.mjs:864

(anonymous) @ index.js:382

_tryToStartAnother @ index.js:253

(anonymous) @ index.js:449

add @ index.js:353

(anonymous) @ index-DPkUyJ8g.mjs:907

await in (anonymous)

(anonymous) @ index.js:68

constructor @ index.js:34

upload @ index-DPkUyJ8g.mjs:842

(anonymous) @ index-DPkUyJ8g.mjs:816

await in (anonymous)

(anonymous) @ index.js:68

constructor @ index.js:34

uploadDirectory @ index-DPkUyJ8g.mjs:787

(anonymous) @ index-DPkUyJ8g.mjs:720

await in (anonymous)

(anonymous) @ index.js:68

constructor @ index.js:34

batchUpload @ index-DPkUyJ8g.mjs:710

onPick @ index-DPkUyJ8g.mjs:1503

invokeWithErrorHandling @ vue.runtime.esm.js:3033

invoker @ vue.runtime.esm.js:1832

(anonymous) @ vue.runtime.esm.js:7500

FilesList.vue:386 [ERROR] files: Error while fetching content {app: 'files', uid: 'testupload', level: 0, error: AbortError: signal is aborted without reason

at o.fetchContent (https://*******/dist/fil\Uffffffff}app: "files"error: AbortError: signal is aborted without reason

at o.fetchContent (https://*******/dist/files-main.js?v=5fed912a-3:1:131282)

at o.onUpload (https://*******/dist/files-main.js?v=5fed912a-3:1:132796)

at sn (https://*******/dist/core-common.js?v=5fed912a-3:1:2366540)

at o.n (https://*******/dist/core-common.js?v=5fed912a-3:1:2359291)

at sn (https://*******/dist/core-common.js?v=5fed912a-3:1:2366540)

at o.$emit (https://*******/dist/core-common.js?v=5fed912a-3:1:2387806)

at o.onUploadCompletion (https://*******/dist/files-main.js?v=5fed912a-3:1:634248)

at $._notifyAll (https://*******/dist/files-main.js?v=5fed912a-3:1:620233)

at https://*******/dist/files-main.js?v=5fed912a-3:1:620992level: 0uid: "testupload"[[Prototype]]: Object

log @ index.mjs:47

error @ index.mjs:65

fetchContent @ FilesList.vue:386

await in fetchContent

onUpload @ FilesList.vue:406

invokeWithErrorHandling @ vue.runtime.esm.js:3033

invoker @ vue.runtime.esm.js:1832

invokeWithErrorHandling @ vue.runtime.esm.js:3033

(anonymous) @ vue.runtime.esm.js:3732

onUploadCompletion @ index-DPkUyJ8g.mjs:1535

_notifyAll @ index-DPkUyJ8g.mjs:669

(anonymous) @ index-DPkUyJ8g.mjs:941

await in (anonymous)

(anonymous) @ index.js:382

_tryToStartAnother @ index.js:253

_next @ index.js:153

(anonymous) @ index.js:415

XMLHttpRequest.send

(anonymous) @ xhr.js:198

(anonymous) @ xhr.js:15

(anonymous) @ dispatchRequest.js:51

Promise.then

_request @ Axios.js:163

request @ Axios.js:40

(anonymous) @ bind.js:12

uploadData @ index-DPkUyJ8g.mjs:65

await in uploadData

(anonymous) @ index-DPkUyJ8g.mjs:864

(anonymous) @ index.js:382

_tryToStartAnother @ index.js:253

_next @ index.js:153

(anonymous) @ index.js:415

XMLHttpRequest.send

(anonymous) @ xhr.js:198

(anonymous) @ xhr.js:15

(anonymous) @ dispatchRequest.js:51

Promise.then

_request @ Axios.js:163

request @ Axios.js:40

(anonymous) @ bind.js:12

uploadData @ index-DPkUyJ8g.mjs:65

await in uploadData

(anonymous) @ index-DPkUyJ8g.mjs:864

(anonymous) @ index.js:382

_tryToStartAnother @ index.js:253

(anonymous) @ index.js:449

add @ index.js:353

(anonymous) @ index-DPkUyJ8g.mjs:907

await in (anonymous)

(anonymous) @ index.js:68

constructor @ index.js:34

upload @ index-DPkUyJ8g.mjs:842

(anonymous) @ index-DPkUyJ8g.mjs:816

await in (anonymous)

(anonymous) @ index.js:68

constructor @ index.js:34

uploadDirectory @ index-DPkUyJ8g.mjs:787

(anonymous) @ index-DPkUyJ8g.mjs:720

await in (anonymous)

(anonymous) @ index.js:68

constructor @ index.js:34

batchUpload @ index-DPkUyJ8g.mjs:710

onPick @ index-DPkUyJ8g.mjs:1503

invokeWithErrorHandling @ vue.runtime.esm.js:3033

invoker @ vue.runtime.esm.js:1832

(anonymous) @ vue.runtime.esm.js:7500

Web server / Reverse Proxy

docker logs -f nextcloud-aio-caddy:

No messages during upload.

iperf3

Network speed test from Helsinki to Oregon. Server to client.

Summary
PS C:\> .\iperf3.exe -c xxxxx -p 5201 -t 10
Connecting to host xxxxx, port 5201
[  5] local 172.31.18.76 port 58807 connected to xxxxx port 5201
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   384 KBytes  3.14 Mbits/sec
[  5]   1.00-2.00   sec  3.75 MBytes  31.5 Mbits/sec
[  5]   2.00-3.00   sec  9.00 MBytes  75.5 Mbits/sec
[  5]   3.00-4.00   sec  19.1 MBytes   160 Mbits/sec
[  5]   4.00-5.00   sec  67.4 MBytes   565 Mbits/sec
[  5]   5.00-6.00   sec   130 MBytes  1.09 Gbits/sec
[  5]   6.00-7.00   sec   282 MBytes  2.37 Gbits/sec
[  5]   7.00-8.00   sec   390 MBytes  3.27 Gbits/sec
[  5]   8.00-9.00   sec   566 MBytes  4.75 Gbits/sec
[  5]   9.00-10.00  sec   573 MBytes  4.81 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  1.99 GBytes  1.71 Gbits/sec                  sender
[  5]   0.00-10.18  sec  1.97 GBytes  1.66 Gbits/sec                  receiver

iperf Done.
PS C:\> .\iperf3.exe -c xxxxx -p 5201 -t 10 -R
Connecting to host xxxxxx, port 5201
Reverse mode, remote host xxxxxxx is sending
[  5] local 172.31.18.76 port 53159 connected to xxxxxx port 5201
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   256 KBytes  2.10 Mbits/sec
[  5]   1.00-2.00   sec  8.75 MBytes  73.4 Mbits/sec
[  5]   2.00-3.00   sec  75.4 MBytes   633 Mbits/sec
[  5]   3.00-4.00   sec  85.1 MBytes   714 Mbits/sec
[  5]   4.00-5.00   sec  87.6 MBytes   735 Mbits/sec
[  5]   5.00-6.00   sec  87.1 MBytes   731 Mbits/sec
[  5]   6.00-7.00   sec  87.6 MBytes   735 Mbits/sec
[  5]   7.00-8.00   sec  88.2 MBytes   740 Mbits/sec
[  5]   8.00-9.00   sec  86.4 MBytes   725 Mbits/sec
[  5]   9.00-10.00  sec  88.6 MBytes   743 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.18  sec   804 MBytes   663 Mbits/sec    0            sender
[  5]   0.00-10.00  sec   695 MBytes   583 Mbits/sec                  receiver

iperf Done.

Configuration

Nextcloud

Summary
root@docker:~# docker exec -u 33 nextcloud-aio-nextcloud php occ config:list system

{

"system": {

"max_chunk_size": 104857600,

"one-click-instance": true,

"one-click-instance.user-limit": 100,

"memcache.local": "\\OC\\Memcache\\APCu",

"apps_paths": [

{

"path": "\/var\/www\/html\/apps",

"url": "\/apps",

"writable": false

},

{

"path": "\/var\/www\/html\/custom_apps",

"url": "\/custom_apps",

"writable": true

}

],

"check_data_directory_permissions": false,

"memcache.distributed": "\\OC\\Memcache\\Redis",

"memcache.locking": "\\OC\\Memcache\\Redis",

"redis": {

"host": "***REMOVED SENSITIVE VALUE***",

"password": "***REMOVED SENSITIVE VALUE***",

"port": 6379,

"timeout": 3,

"read_timeout": 10

},

"overwritehost": "***REMOVED SENSITIVE VALUE***",

"overwriteprotocol": "https",

"passwordsalt": "***REMOVED SENSITIVE VALUE***",

"secret": "***REMOVED SENSITIVE VALUE***",

"trusted_domains": [

"localhost",

"***REMOVED SENSITIVE VALUE***"

],

"datadirectory": "***REMOVED SENSITIVE VALUE***",

"dbtype": "pgsql",

"version": "33.0.5.1",

"overwrite.cli.url": "https:\/\/\/",

"dbname": "***REMOVED SENSITIVE VALUE***",

"dbhost": "***REMOVED SENSITIVE VALUE***",

"dbtableprefix": "oc_",

"dbuser": "***REMOVED SENSITIVE VALUE***",

"dbpassword": "***REMOVED SENSITIVE VALUE***",

"installed": true,

"instanceid": "***REMOVED SENSITIVE VALUE***",

"maintenance": false,

"updatechecker": false,

"loglevel": 0,

"log_type": "file",

"logfile": "\/var\/www\/html\/data\/nextcloud.log",

"log_rotate_size": 10485760,

"log.condition": {

"apps": [

"admin_audit"

]

},

"preview_max_x": 2048,

"preview_max_y": 2048,

"jpeg_quality": 60,

"enabledPreviewProviders": {

"1": "OC\\Preview\\Image",

"2": "OC\\Preview\\MarkDown",

"3": "OC\\Preview\\MP3",

"4": "OC\\Preview\\TXT",

"5": "OC\\Preview\\OpenDocument",

"6": "OC\\Preview\\Movie",

"7": "OC\\Preview\\Krita",

"0": "OC\\Preview\\Imaginary",

"23": "OC\\Preview\\ImaginaryPDF"

},

"enable_previews": true,

"upgrade.disable-web": true,

"mail_smtpmode": "smtp",

"trashbin_retention_obligation": "auto, 30",

"versions_retention_obligation": "auto, 30",

"activity_expire_days": 30,

"simpleSignUpLink.shown": false,

"share_folder": "\/Shared",

"one-click-instance.link": "https:\/\/nextcloud.com\/all-in-one\/",

"upgrade.cli-upgrade-link": "https:\/\/github.com\/nextcloud\/all-in-one\/discussions\/2726",

"updatedirectory": "\/nc-updater",

"maintenance_window_start": 100,

"allow_local_remote_servers": true,

"davstorage.request_timeout": 3600,

"documentation_url.server_logs": "https:\/\/github.com\/nextcloud\/all-in-one\/discussions\/5425",

"htaccess.RewriteBase": "\/",

"dbpersistent": false,

"auth.bruteforce.protection.enabled": true,

"ratelimit.protection.enabled": true,

"files_external_allow_create_new_local": false,

"trusted_proxies": "***REMOVED SENSITIVE VALUE***",

"preview_imaginary_url": "***REMOVED SENSITIVE VALUE***",

"preview_imaginary_key": "***REMOVED SENSITIVE VALUE***",

"first_run_wizard.enabled": false,

"skeletondirectory": "",

"mail_sendmailmode": "smtp",

"mail_from_address": "***REMOVED SENSITIVE VALUE***",

"mail_domain": "***REMOVED SENSITIVE VALUE***",

"mail_smtphost": "***REMOVED SENSITIVE VALUE***",

"mail_smtpauth": true,

"mail_smtpname": "***REMOVED SENSITIVE VALUE***",

"mail_smtppassword": "***REMOVED SENSITIVE VALUE***",

"mail_smtpport": "587",

"objectstore": {

"class": "\\OC\\Files\\ObjectStore\\S3",

"arguments": {

"bucket": "***REMOVED SENSITIVE VALUE***",

"hostname": "hel1.your-objectstorage.com",

"key": "***REMOVED SENSITIVE VALUE***",

"region": "hel1",

"secret": "***REMOVED SENSITIVE VALUE***",

"port": 443,

"use_path_style": true,

"use_ssl": true,

"uploadPartSize": 134217728,

"concurrency": 50,

"verify_bucket_exists": false,

"useMultipartCopy": true

}

},

"serverid": 445,

"log_type_audit": "file",

"logfile_audit": "\/var\/www\/html\/data\/audit.log",

"update_channel": "stable",

"forbidden_filename_basenames": [

"con",

"prn",

"aux",

"nul",

"com0",

"com1",

"com2",

"com3",

"com4",

"com5",

"com6",

"com7",

"com8",

"com9",

"com\u00b9",

"com\u00b2",

"com\u00b3",

"lpt0",

"lpt1",

"lpt2",

"lpt3",

"lpt4",

"lpt5",

"lpt6",

"lpt7",

"lpt8",

"lpt9",

"lpt\u00b9",

"lpt\u00b2",

"lpt\u00b3"

],

"forbidden_filename_characters": [

"<",

">",

":",

"\"",

"|",

"?",

"*",

"\\",

"\/"

],

"forbidden_filename_extensions": [

" ",

".",

".filepart",

".part"

],

"DOMAIN": "",

"AIO_VERSION": "v13.2.1"

}

}


Apps

Summary
Enabled:

- activity: 6.0.0

- admin_audit: 1.23.0

- bruteforcesettings: 6.0.0

- calendar: 6.4.2

- circles: 33.0.0

- cloud_federation_api: 1.17.0

- comments: 1.23.0

- contacts: 8.5.1

- contactsinteraction: 1.14.1

- dashboard: 7.13.0

- dav: 1.36.0

- deck: 1.17.3

- federatedfilesharing: 1.23.0

- federation: 1.23.0

- files: 2.5.0

- files_downloadlimit: 5.1.0

- files_external: 1.25.1

- files_fulltextsearch: 33.0.0

- files_pdfviewer: 6.0.0

- files_reminders: 1.6.0

- files_sharing: 1.25.2

- files_trashbin: 1.23.0

- files_versions: 1.26.0

- fulltextsearch: 33.0.0

- fulltextsearch_elasticsearch: 33.0.0

- groupfolders: 21.0.7

- integration_dropbox: 5.0.0

- logreader: 6.0.0

- lookup_server_connector: 1.21.0

- mail: 5.9.1

- nextcloud-aio: 0.8.0

- notes: 6.0.0

- notifications: 6.0.0

- notify_push: 1.3.3

- oauth2: 1.21.0

- password_policy: 5.0.0

- passwords: 2026.5.10

- polls: 9.1.4

- privacy: 5.0.0

- profile: 1.2.0

- provisioning_api: 1.23.0

- recommendations: 6.0.0

- related_resources: 4.0.0

- richdocuments: 10.2.0

- serverinfo: 5.0.0

- settings: 1.16.0

- sharebymail: 1.23.0

- sociallogin: 6.5.2

- spreed: 23.0.6

- support: 5.0.0

- survey_client: 5.0.0

- systemtags: 1.23.0

- tasks: 0.17.1

- text: 7.0.1

- theming: 2.8.0

- twofactor_backupcodes: 1.22.0

- updatenotification: 1.23.0

- user_status: 1.13.0

- viewer: 6.0.0

- webhook_listeners: 1.5.0

- whiteboard: 1.5.9

- workflowengine: 2.15.0

Disabled:

- app_api: 33.0.0 (installed 32.0.0)

- encryption: 2.21.0

- files_antivirus: 6.2.0 (installed 6.2.0) [Temporarily disabled for testing]

- firstrunwizard: 6.0.0 (installed 5.0.0-dev.0)

- news: 28.5.1 (installed 28.5.1)

- nextcloud_announcements: 5.0.0 (installed 4.0.0-dev.0)

- photos: 6.0.0 (installed 5.0.0-dev.1)

- suspicious_login: 11.0.0 [Temporarily disabled for testing]

- twofactor_nextcloud_notification: 7.0.0

- twofactor_totp: 15.0.0 (installed 14.0.0)

- user_ldap: 1.24.0

- weather_status: 1.13.0 (installed 1.12.0)

Thank you so much for helping us. Please let me know if you need any further details.

Hello @TimLoes, welcome to the Nextcloud community! :handshake:

I have no good solution but maybe few hints you could try out.

In general you should place your server close to the majority of the users. If remote users still can’t live with the performance maybe it’s worth to run multiple instances of Nextcloud located close to the users.

The question is also if the problem is relevant for daily usage - do you expect people to do such uploads all the time on only during initial upload stage? In most scenarios using desktop client it doesn’t really matter for the user if upload completes within 10s oder 100s as long it is reliable..

And not the last advice - Nextcloud is designed for collaboration like sharing, co-editing etc - if you are looking for simple dumb storage sync faster alternatives exist.

  • if “closer” client performs faster the problem must be on the client or in transit. I remember huge latency reduce transfer speed (because of waiting for TCP ACK) - see details below
  • I was testing uploads shortly (in local WiFi) and both web and desktop client max out the network speed with big files (with small files processing on the server significantly reduces transfer performance) - both performing at same level looks like some local cap
  • a gap between chunks is likely because the server need time to combine the chunks - placing tmp storage on fast local drive might improve this operation
  • if you believe connections are stable you could adjust chunk sizes - bigger chunk require less combine operations at the cost of bigger disturbance if one transfer fails - you stated changes are not applied - maybe it’s worth to dig deeper. desktop client has it’s own local chunking config - double check if it helps

maybe worth to carefully review https://docs.nextcloud.com/server/stable/admin_manual/configuration_files/big_file_upload_configuration.html

latency impact on network bandwith

The article is from MS but mechanics are the same everywhere:

Total achievable throughput in bytes = TCP receive window size in bytes * (1 / connection latency in seconds)

which translates into

For example, for a 1Gbps connection that has a latency of 10 ms, the total achievable throughput is only 51 Mbps.

from: TCP receive window vs latency and linux-related write-up How to Tune TCP Receive Window Size on Linux

Totally unsupported!

As an experiment in the past, I had set up three Nextcloud servers in a relay configuration to see whether local synchronization could work, uploads and synchronization delays.

One possible workaround may be to deploy regional Nextcloud instances and use the Nextcloud desktop client to replicate data between them.

I have tested a relay configuration using three Nextcloud servers. It does work, but there are some challenges. During synchronization, a few file conflicts can occur as changes bounce around the network between servers, particularly if files are being modified at multiple locations.

The initial setup can also be tricky and may require pausing clients and deleting the local sync database before establishing the replication chain.

The biggest limitation I found is that there does not appear to be an officially supported headless Nextcloud client for Linux servers. Running the desktop client on a server generally requires a graphical environment or additional workarounds, making server-to-server replication more difficult than it should be. A supported headless sync client would make regional replication and multi-site deployments much easier to implement and automate.

In my testing, once the initial synchronization completed, the conflict rate was relatively low unless files were being actively edited at multiple sites. That makes the approach seem more practical than experimental, particularly for workloads that are primarily file distribution, backup, or archival rather than simultaneous collaborative editing.

While this approach is not as elegant as true geo-replication or distributed object storage, it may provide a practical solution for organizations with users spread across multiple continents. Users upload to a nearby server at local speeds, while long-distance synchronization occurs in the background.

→ there is a CLI client Command Line Client — Nextcloud latest Administration Manual latest documentation not exactly headless it performs “one time sync” - but as long you run frequently it should be good.

It is not supported and I would really not recommend to sync same local folder with multiple targets (doesn’t matter which sync service like Dropbox or GoogleDrive).

One could imagine many different setups - it depends if a single “master” data set is required or if there are multiple user populations primarily working on some subset and occasionally access data from remote locations.

Thanks a lot @smokingwheels and @wwe .

We want to use Nextcloud not only as a file hoster, but also for collaboration, etc. So running multiple Nextcloud instances could technically work, but I doubt that it would be accepted by the user base. We mostly only have a bunch of people in the countries, everything works internationally.

The main issue, which would solve almost the entire issue, would be to have the desktop client and web-interface to increase the upload speed. People don’t mind latency too much, but the upload speed is sometimes critical, as we work with videos. So, yes, we will do big uploads on a frequent basis.

Once thing I just cant really wrap my head around, is how Nextcloud/desktop client have 5 MB/s upload, while a 20 minutes AI developed script doing the same upload and using the same WebDAV reaches 50 MB/s. The only thing the AI script did differently was staggering the chunk starts 1 second apart. Staggering the chunks should only fill the idle gap, but still wouldn’t lift the general upload speed.

Upload from long distance with web-ui:

Upload from same windows client, long distance, with staggering curl script:

Also iperf3 measured 85 MB/s. But sure, there is no data handling involved, not fair to compare.

Also: Upload speed is faster when closer to the server, but it also is very fluctuating. It still doesn’t look very optimized. I guess the issue just grows with distance.

AI script upload with curl reaching up to 600 Mbps
# nextcloud_chunked_upload.ps1
# Parallel chunked upload to Nextcloud via WebDAV chunked-upload API

# ============ CONFIG — EDIT THESE ============
$file          = "C:\testfile.dat"
$server        = "https://your-nextcloud-instance.com"   # no trailing slash
$username      = "your-username"
$password      = "your-password"                          # use an app password if 2FA is on
$remoteName    = "testfile.dat"                            # final filename on Nextcloud
$chunks        = 10
$offsetSeconds = 1                                        # stagger between chunk starts (0 to disable)
# =============================================

# --- Validate config ---
if ($server -match "your-nextcloud-instance" -or $username -match "your-username") {
    Write-Error "You still have placeholder values. Edit the CONFIG section first!"
    exit 1
}
if (-not (Test-Path $file)) { Write-Error "File $file not found!"; exit 1 }

$curlPath = (Get-Command curl.exe -ErrorAction SilentlyContinue).Source
if (-not $curlPath) { $curlPath = "C:\Windows\System32\curl.exe" }
Write-Host "Using curl: $curlPath"

$fileInfo  = Get-Item $file
$fileSize  = $fileInfo.Length
$fullPath  = $fileInfo.FullName
$chunkSize = [Math]::Ceiling($fileSize / $chunks)

$uploadId   = "ncchunk-" + (Get-Random)
$uploadBase = "$server/remote.php/dav/uploads/$username/$uploadId"
$finalDest  = "$server/remote.php/dav/files/$username/$remoteName"

Write-Host "File:        $fullPath ($([Math]::Round($fileSize/1MB,2)) MB)"
Write-Host "Chunks:      $chunks x $([Math]::Round($chunkSize/1MB,2)) MB"
Write-Host "Upload base: $uploadBase"
Write-Host "Final dest:  $finalDest`n"

# ============ STEP 1: Create upload session (MKCOL) ============
Write-Host "Creating upload session..."
$mkcolStatus = & $curlPath -s -S -X MKCOL -u "${username}:${password}" `
    -w "%{http_code}" -o NUL "$uploadBase"
if ($mkcolStatus -notin @("201","405")) {
    # 405 = already exists, which is fine
    Write-Warning "MKCOL returned $mkcolStatus (expected 201). Continuing anyway..."
} else {
    Write-Host "Upload session created (status $mkcolStatus)."
}

# ============ STEP 2: Parallel chunk uploads ============
$uploadScriptBlock = {
    param($chunkIndex, $startPos, $endPos, $fullPath, $uploadBase, $username, $password, $delay, $curlPath)

    Start-Sleep -Seconds $delay

    # Read this chunk's bytes from the source file
    $stream = [System.IO.File]::OpenRead($fullPath)
    $currentChunkSize = $endPos - $startPos + 1
    $buffer = New-Object byte[] $currentChunkSize
    $stream.Position = $startPos
    [void]$stream.Read($buffer, 0, $currentChunkSize)
    $stream.Close()

    # Write chunk to a temp file
    $chunkFile = [System.IO.Path]::GetTempFileName()
    [System.IO.File]::WriteAllBytes($chunkFile, $buffer)

    # Zero-padded chunk name (Nextcloud assembles in lexical order)
    $chunkName = "{0:D8}" -f ($chunkIndex + 1)
    $chunkUrl  = "$uploadBase/$chunkName"

    $sw = [System.Diagnostics.Stopwatch]::StartNew()

    $curlArgs = @(
        "-X", "PUT",
        "-u", "${username}:${password}",
        "-T", $chunkFile,
        "-o", "NUL",
        "-s", "-S",
        "-w", "%{http_code}|%{time_total}|%{speed_upload}",
        $chunkUrl
    )
    $result = & $curlPath @curlArgs 2>&1
    $sw.Stop()

    Remove-Item $chunkFile -ErrorAction SilentlyContinue

    $resultStr = ($result | Out-String).Trim()
    $parts = $resultStr -split '\|'

    [PSCustomObject]@{
        ChunkIndex    = $chunkIndex
        StartDelay    = $delay
        SizeMB        = [Math]::Round($currentChunkSize/1MB, 2)
        ChunkUrl      = $chunkUrl
        HttpCode      = if ($parts.Length -ge 1) { $parts[0] } else { "???" }
        CurlTime      = if ($parts.Length -ge 2 -and $parts[1] -match '^\d') { [Math]::Round([double]$parts[1], 2) } else { 0 }
        CurlSpeedMBps = if ($parts.Length -ge 3 -and $parts[2] -match '^\d') { [Math]::Round([double]$parts[2]/1MB, 2) } else { 0 }
        ElapsedSec    = [Math]::Round($sw.Elapsed.TotalSeconds, 2)
        RawOutput     = $resultStr
    }
}

Write-Host "`nLaunching $chunks parallel chunk uploads...`n"
$overallStart = Get-Date
$jobs = @()

for ($i = 0; $i -lt $chunks; $i++) {
    $startPos = $i * $chunkSize
    $endPos   = [Math]::Min(($startPos + $chunkSize - 1), ($fileSize - 1))
    $delay    = $i * $offsetSeconds

    Write-Host "Queuing chunk $($i+1)/$chunks (start after ${delay}s, bytes $startPos-$endPos)"

    $jobs += Start-Job -ScriptBlock $uploadScriptBlock -ArgumentList `
        $i, $startPos, $endPos, $fullPath, $uploadBase, $username, $password, $delay, $curlPath
}

Write-Host "`nWaiting for completion...`n"
$jobs | Wait-Job | Out-Null
$results = $jobs | Receive-Job
$jobs | Remove-Job

$uploadWallTime = ((Get-Date) - $overallStart).TotalSeconds

# ============ STEP 3: Assemble final file (MOVE) ============
Write-Host "`nAssembling final file -> $finalDest"
$moveStatus = & $curlPath -s -S -X MOVE -u "${username}:${password}" `
    -H "Destination: $finalDest" `
    -H "OC-Total-Length: $fileSize" `
    -w "%{http_code}" -o NUL `
    "$uploadBase/.file"
Write-Host "Assembly status: $moveStatus"

# ============ RESULTS ============
Write-Host "`n========== CHUNK RESULTS =========="
$allOk = $true
$results | Sort-Object ChunkIndex | ForEach-Object {
    Write-Host "`nChunk $($_.ChunkIndex + 1):"
    Write-Host "  Start delay:  $($_.StartDelay)s"
    Write-Host "  Size:         $($_.SizeMB) MB"
    Write-Host "  HTTP Status:  $($_.HttpCode)"
    Write-Host "  Upload time:  $($_.CurlTime)s (curl) / $($_.ElapsedSec)s (incl. delay+read)"
    Write-Host "  Speed:        $($_.CurlSpeedMBps) MB/s"
    if ($_.HttpCode -notin @("200","201","204")) {
        $allOk = $false
        Write-Warning "  Failed! Raw output: $($_.RawOutput)"
        Write-Host    "  URL was: $($_.ChunkUrl)"
    }
}

$sumCurlTime = ($results | Measure-Object -Property CurlTime -Sum).Sum
$avgSpeed    = ($results | Measure-Object -Property CurlSpeedMBps -Average).Average

Write-Host "`n========== OVERALL SUMMARY =========="
Write-Host "Total file size:      $([Math]::Round($fileSize/1MB,2)) MB"
Write-Host "Number of chunks:     $chunks"
Write-Host "Offset per chunk:     $offsetSeconds s"
Write-Host "Upload wall-clock:    $([Math]::Round($uploadWallTime,2)) s"
Write-Host "Sum of chunk times:   $([Math]::Round($sumCurlTime,2)) s"
Write-Host "Avg chunk speed:      $([Math]::Round($avgSpeed,2)) MB/s"
Write-Host "Effective throughput: $([Math]::Round($fileSize/$uploadWallTime/1MB,2)) MB/s"
if ($allOk -and $moveStatus -in @("201","204")) {
    Write-Host "RESULT: SUCCESS - file assembled at $finalDest" -ForegroundColor Green
} else {
    Write-Host "RESULT: Some chunks or the assembly FAILED - see warnings above" -ForegroundColor Yellow
}
Write-Host "====================================="

There got to be a way to optimize desktop client and web-interface, don’t you think? That would be such a great win for the entire NC world. :slight_smile: (I guess… )

Edit: Sorry, there were a few more questions I didnt answer yet.

Regarding home internet speed: Yes, the same in my case. The internet speed at home was maxed out. But thats because I’m in Germany. Internet here is slow. A lot of other countries and people I work with have much faster connections, e.g. 400 Mbps upload in Brazil or Spain where our media people sit. USA is generally as slow as Germany, I think.

Regarding gaps in between chunks: True, file handling, S3 push or something like that on the server. Still doesn’t have to idle the bandwith. It could just work on a different chunk in the meantime. Assembly is only done at the end, once all chunks are uploaded.

Regarding bigger chunks: I tried to play around with the setting, but it looks like web-ui and desktop clients don’t really take the value into consideration. They just always upload with 100MB chunks.

in my tests with multi-GB-files it’s maxing out the network speed using both web-UI and desktop client - and no it is not my internet link, I’m close I was to saturating 1GBit/s network to my server (bypass internet loop using splitbraindns ) - now something is different and I see only 30MBit/s on the same system - must double check.

UPDATE: it’s even more weird.. testing WEB upload using 6x600MB files I see following strange behaviour

  • i planned to verify your chunk theory: but I see no drop between chunks
  • transfer started at 80MB/s and dropped to 30 MB/s later (FIrefox)
  • another try (Chromium) started at ~30MB/s and stayed constant (with 1.2 drops to 20MB/s))

at the end - Nextcloud itself is capable to consume more than 5MB/s..

I’m having hard time to understand the difference in curl script and web UI… but my conclusion remains the same - if closer clients are faster it must have something to do with network conditions.

they do. I’m too lazy to test right now but in the past I successfully tested different chunk sizes (without any impact on desktop client performance)