Definitive Guide to using Minio as NextCloud Primary Storage

Minio is an on-premises object storage server that can be deployed as a Minio cluster (with local storage) or as a gateway to other object storage services with their own API such as Backblaze B2, Azure Blob Storage, and Google Cloud Storage. Because Minio exposes a S3 compatible endpoint, virtually any application that supports the AWS SDK can be integrated with it. According to Minio, half of the Fortune 500 have deployed Minio for storage, including for cloud-native workloads such as Kubernetes.

NextCloud, an enterprise file sync & share (EFSS) frontend for a variety of storage backends, can be configured to use S3 as primary storage. Normally NextCloud relies on conventional storage such as block volumes and RAID arrays that need to be scaled using tools such as LVM as the volume of data stored on the deployment grows. Using S3 as primary storage instead simplifies scaling NextCloud to ever-growing volumes of data, because adding additional storage to a distributed Minio cluster (up to 32 nodes per cluster, with federation of clusters supported) can be achieved with zero downtime.

If you are using an object storage service such as Backblaze B2, Minio can translate S3 API requests from NextCloud to B2 API requests, requiring no code changes or additional apps to be installed on your NextCloud instance.

Although Minio is S3 compatible, like most other S3 compatible services, it is not 100% S3 compatible. This means for example, you have to use the ObjectUploader class instead of the MultipartUploader function to upload large files to Backblaze B2 through Minio. Also, only V2 signatures have been implemented by Minio, not V4 signatures.

Creating a path using the Minio S3-B2 gateway is not supported, because the B2 API does not have an equivalent to S3 API where “folders” can be created. Technically, the concept of a “folder” does not exist with any object storage specification, because a path is simply part of an object’s name.

If you are having problems with setting up Minio, or integrating NextCloud with Minio, we’ve tested various use cases where our team can provide paid NextCloud support and consulting.

Whenever you configure NextCloud with S3 as primary storage, it must be configured when you initially install NextCloud for the first time. The reason for this is because on deployments using a S3 backend, the files that you upload to NextCloud are stored as urn:oid objects rather than with their original file names. The original file names and other metadata are stored in the DB, which should be MySQL or PostgreSQL. SQLite is not recommended except for very small testing instances, because of its slow performance.

A minimal deployment of Minio can be spun up using the minio/minio container published on Docker Hub. Here is the documentation on Github for the Minio B2 Gateway.

The MINIO_ACCESS_KEY= and MINIO_SECRET_KEY= environment variables should be set to the Master Application Key found in the App Keys portion of the Backblaze B2 account area. This will also correspond to the ‘key’ and ‘secret’ used when configuring NextCloud, and for accessing Minio from its web interface.

The Minio B2 Gateway can reside on either the same server as the NextCloud app server (at localhost:9000), or a separate server in close proximity. If using a separate server on a separate LAN, HTTPS should always be used to protect data in-transit to and from the Minio gateway. This can be achieved by setting up Nginx as a reverse proxy that passes external HTTPS requests from port 443 to port 9000 on localhost on the Minio server.

B2 as Primary Storage in NextCloud

After extracting the NextCloud application to your webroot directory, you need to apply the following patch using git by creating this patch file (e.g. 288.diff) in nextcloud/lib and running git apply -v 288.diff.

Index: lib/private/Files/ObjectStore/S3ObjectTrait.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- lib/private/Files/ObjectStore/S3ObjectTrait.php     (revision cde1c8b9a3502074e0d811daaedd909d6352e0b3)
+++ lib/private/Files/ObjectStore/S3ObjectTrait.php     (date 1569166430137)
@@ -82,11 +82,12 @@
                   	$count += $read;
                });
 
-               $uploader = new MultipartUploader($this->getConnection(), $countStream, [
-                       'bucket' => $this->bucket,
-                       'key' => $urn,
-                       'part_size' => S3_UPLOAD_PART_SIZE
-               ]);
+               $uploader = new ObjectUploader(
+                       $this->getConnection(),
+                       $this->getBucket(),
+                       $urn,
+                       $countStream
+               );
 
                try {
                     	$uploader->upload();

Here is an example storage.config.php which you should put in nextcloud/config prior to running the setup wizard for NextCloud. For integrating NextCloud with Minio, the use_path_style and legacy_path options must be set to true.

use_path_style forces NextCloud to use bucket names in path format (minio.example.com/%(bucket)s) instead of subdomains (%(bucket)s.minio.example.com). If you wanted to use the latter format, you would need to create a hostname as an alias to Minio using a CNAME record.

legacy_path instructs NextCloud to use V2 signatures instead of V4 signatures when authenticating to Minio. Minio does not currently support V4 signatures.

The bucket should be created using the B2 web interface or command line prior to installing NextCloud. The name must be globally unique across all B2 regions. There are currently two Backblaze regions, one in Sacramento (US West) and Ireland (EU Central). Make sure to choose the Backblaze region closest to your NextCloud and Minio server – otherwise the performance will be extremely slow.

The region does not have to be specified in this config because it is handled by Minio and the B2 API.

<?php $CONFIG = [ 'objectstore' => [
                'class' => 'OC\\Files\\ObjectStore\\S3',
                'arguments' => [
                  'bucket' => 'cloudstoreb2',
                  'autocreate' => false,
                  'key'    => 'redacted',
                  'secret' => 'redacted',
                  'hostname' => 'minio.example.com',
                  'port' => 443,
                  'use_ssl' => true,
                  'region' => '',
                  // required for some non Amazon S3 implementations
                  'use_path_style' => true,
                  'legacy_auth' => true
                ],
        ],
];

After creating the config file, and ensuring that the nextcloud folder is owned by your web server user, continue to your browser to complete the setup wizard. Be patient and do not refresh the page, while the user directory is created for the first time on Backblaze B2 through the Minio gateway.

To upload files larger than 10 MB, you need to enable the Default Encryption Module app in NextCloud – even if you do not plan to enable server-side encryption (it is not mandatory). Otherwise when uploading any file > 10 MB, you will encounter an error similar to:

Expected filesize of 10000000 bytes but read (from Nextcloud client) and wrote (to Nextcloud storage) 15242880 bytes

We do not recommend using NextCloud’s server-side encryption with object storage because this use case has not been thoroughly tested by the core developers and may lead to data loss.

When the Default Encryption Module is enabled but server-side encryption is not, the toast message “Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files” appears in the NextCloud dashboard for all users. The message is irrelevant because server-side encryption is not in use. To prevent the pop-up, comment out lines 75 to 80 in nextcloud/apps/encryption/lib/Controller/StatusController.php.

                       	/* case Session::INIT_EXECUTED:
                                $status = 'interactionNeeded';
                               	$message = (string)$this->l->t(
                                       	'Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files.'
                                );
                               	break; */
B2 as External Storage in NextCloud

Currently, mounting B2 buckets using the External Storage app in NextCloud using the “Amazon S3” option (through Minio) is not supported. If the bucket does not already exist, it will be created successfully, but subsequent attempts to access it will be met with a BucketAlreadyOwnedByYou error.

If you attempt to add any B2 bucket as external storage, it will prevent the NextCloud desktop client from syncing correctly for any users who are assigned access to the share.