Slow downloads / uploads with Docker php-fpm and nginx

Nextcloud version (eg, 20.0.5): 27.0.0
Operating system and version (eg, Ubuntu 20.04): Linux 6.1.34-Unraid x86_64 (Unraid 6.12.1 Linux but Nextcloud in Docker)
Apache or nginx version (eg, Apache 2.4.25): nginx (php-fpm)
PHP version (eg, 7.4): 8.2.7
Database mysql 11.0.02
image


The issue you are facing:
Download and upload are not as fast as I would expect them. Both are about 6 MB/s. Nextcloud and the database are running in Docker on an SSD with an ZFS filesystem. Data is written on an HDD with an ZFS filesystem. I have customized the Docker images according to the examples of Nextcloud. That’s why I have many extensions. I have a nextcloud-web container for nginx and a nextcloud container for the app. I also have many apps installed but that shouldn’t impact the download/upload speed.

I’m routing the traffic through NGINX Proxy Manager with this additional config:

client_max_body_size 0;
proxy_request_buffering off;
proxy_max_temp_file_size 0;

include /snippets/authelia-location.conf;

location / {
    include /snippets/authelia-proxy.conf;
    # commented because not needed
    # include /snippets/authelia-authrequest.conf; 
    proxy_pass $forward_scheme://$server:$port;
}

location /.well-known/carddav {
    return 301 $scheme://$host/remote.php/dav;
}

location /.well-known/caldav {
    return 301 $scheme://$host/remote.php/dav;
}

location /.well-known/webfinger {
    return 301 $scheme://$host/index.php/.well-known/webfinger;
}

location /.well-known/nodeinfo {
    return 301 $scheme://$host/index.php/.well-known/nodeinfo;
}

I need the first lines to download files bigger than 1GB. Otherwise, the download fails. The installation of my Nextcloud is fresh. From NGINX Proxy Manager it goes over Cloudflare where I proxy my domain and that’s it. I got a FritzBox as router and using AdGuard Home on my server as network DNS if this is important.

My download speed is way higher for example:

The output of your config.php file in /path/to/nextcloud (make sure you remove any identifiable information!):

<?php
$CONFIG = array (
  'memcache.local' => '\\OC\\Memcache\\APCu',
  'apps_paths' => 
  array (
    0 => 
    array (
      'path' => '/var/www/html/apps',
      'url' => '/apps',
      'writable' => false,
    ),
    1 => 
    array (
      'path' => '/var/www/html/custom_apps',
      'url' => '/custom_apps',
      'writable' => true,
    ),
  ),
  'memcache.distributed' => '\\OC\\Memcache\\Redis',
  'memcache.locking' => '\\OC\\Memcache\\Redis',
  'redis' => 
  array (
    'host' => 'redis',
    'password' => '',
    'port' => 6379,
  ),
  'instanceid' => 'XYZ',
  'passwordsalt' => 'XYZ',
  'secret' => 'XYZ',
  'trusted_domains' => 
  array (
    0 => '192.168.178.31:8666',
    1 => 'cloud.test.de',
  ),
  'datadirectory' => '/var/www/html/data',
  'dbtype' => 'mysql',
  'version' => '27.0.0.8',
  'overwritehost' => 'cloud.test.de',
  'overwrite.cli.url' => 'https://cloud.test.de/',
  'overwriteprotocol' => 'https',
  'dbname' => 'nextcloud',
  'dbhost' => 'nextcloud-db:3306',
  'dbport' => '',
  'dbtableprefix' => 'oc_',
  'mysql.utf8mb4' => true,
  'dbuser' => 'XYZ',
  'dbpassword' => 'XYZ',
  'installed' => true,
  'default_language' => 'de',
  'default_phone_region' => 'DE',
  'default_locale' => 'de_DE',
  'memories.exiftool' => '/var/www/html/custom_apps/memories/exiftool-bin/exiftool-amd64-glibc',
  'memories.vod.path' => '/var/www/html/custom_apps/memories/exiftool-bin/go-vod-amd64',
  'memories.vod.ffmpeg' => '/usr/bin/ffmpeg',
  'memories.vod.ffprobe' => '/usr/bin/ffprobe',
  'ldapProviderFactory' => 'OCA\\User_LDAP\\LDAPProviderFactory',
  'ncd_admin_settings' => 
  array (
    'disallow_aria2_settings' => '1',
  ),
  'memories.gis_type' => 1,
  'trashbin_retention_obligation' => 'auto',
  'auth.bruteforce.protection.enabled' => false,
  'theme' => '',
  'loglevel' => 2,
  'maintenance' => false,
  'trusted_proxies' => 
  array (
    0 => '173.245.48.0/20',
    1 => '103.21.244.0/22',
    2 => '103.22.200.0/22',
    3 => '103.31.4.0/22',
    4 => '141.101.64.0/18',
    5 => '108.162.192.0/18',
    6 => '190.93.240.0/20',
    7 => '188.114.96.0/20',
    8 => '197.234.240.0/22',
    9 => '198.41.128.0/17',
    10 => '162.158.0.0/15',
    11 => '104.16.0.0/13',
    12 => '104.24.0.0/14',
    13 => '172.64.0.0/13',
    14 => '131.0.72.0/22',
    15 => '2400:cb00::/32',
    16 => '2606:4700::/32',
    17 => '2803:f800::/32',
    18 => '2405:b500::/32',
    19 => '2405:8100::/32',
    20 => '2a06:98c0::/29',
    21 => '2c0f:f248::/32',
  ),
  'forwarded_for_headers' => 
  array (
    0 => 'HTTP_CF_CONNECTING_IP',
  ),
  'app_install_overwrite' => 
  array (
    0 => 'camerarawpreviews',
    1 => 'checksum',
    2 => 'keeweb',
    3 => 'timetracker',
    4 => 'registration',
    5 => 'ncdownloader',
    6 => 'files_linkeditor',
    7 => 'metadata',
    8 => 'memories',
    9 => 'side_menu',
    10 => 'sharerenamer',
    11 => 'files_bpm',
    12 => 'hibp',
  ),
);

The output of your Apache/nginx/system log in /var/log/____:

Sorry where and what? Cannot get the logs of nextcloud-web.

Output errors in nextcloud.log in /var/www/ or as admin user in top right menu, filtering for errors. Use a pastebin service if necessary.

No errors. Also no integrity check errors.


Docker stats of the running containers.

Same for the upload. And the files page is also very slow on initial load. But only the files app page. Nothing else. Not browsing in files or settings or something. Any idea what could be the limiting factor?

Btw I did everything like here in the example: docker/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf at master · nextcloud/docker · GitHub

I am wondering if it is necessary to adjust the client_max_body_size value here too? I mean it seems to work even without any changes from nginx to nginx.

Given you Speedtest results, both your uploads and downloads won’t be able to exceed ~6.125 MB/s (i.e. 49.6 Mbit/s) when you’re in the same physical location as your Unraid server.

This is because of your current network capabilities and, in particular, reliance on Cloudflare as your de facto proxy…

An upload would take the following network path:

workstation → Lan → Internet_link_up → cloudflare → Internet_link_down → npm → web-nginx → app-fpm (NC)

And a download:

app-fpm (NC) → web-nginx → npm → Internet_link_up → cloudflare → Internet_link_down → Lan → workstation

So the upload speed of your Internet link is your limiting factor since you’re using Cloudflare.

From outside of your LAN, you could probably get faster upload speeds to your NC instance (assuming wherever you’re connecting from has a faster link then 49 Mbit/s), but downloads would still be confined by your NC server’s Internet link’s upload speed constraints.

There are some caveats with using Cloudflare you might want to understand (and, in some cases, possible workarounds):

Thank you for your extensive answer.

I didn’t recognize any problems using Cloudflare Proxy and Nextcloud. Only download/upload speed. And as I remember it was better when I used NextCloudPi in Docker on less power server in the same setup.

Can you explain to me what this means:

  • Using Cloudflare Tunnel potentially slows down Nextcloud by a lot since local access via the configured domain is not possible since TLS proxying is in that case offloaded to Cloudflares infrastructure. You can fix this by setting up your own reverse proxy that handles TLS proxying locally.

I would do it if I know what they mean. Oh okay it is about Cloudflare Tunnel. I am not using Tunnel so nvm I guess.

Cloudflare DNS with Proxied mode enabled (the default with CF) has the same result as using Cloudflare Tunneling:

What it means is that if you rely on CF’s proxying services even your local connections to your server (even if you’re sitting right next to it) will go out to the Internet and back before hitting your server. This is only an issue if your server is located close to you rather than hosted elsewhere in a data center. To workaround this issue, you either don’t use Cloudflare or you have to take extra steps to bypass Cloudflare when you’re near your server.