Picking between OpenCloud vs Nextcloud, with ownCloud still in the frame, is really a choice between two server designs. OpenCloud and ownCloud Infinite Scale share one Go codebase that runs as a single container with no database. Nextcloud is a PHP application that needs MariaDB or PostgreSQL, Redis and a cron runner beside it. That difference shows up in memory, disk, upgrades and how your files sit on disk, and it matters more than any feature list.
We installed all three with Docker Compose on identical Ubuntu 26.04 VMs and measured idle RAM and CPU, container count, disk footprint and WebDAV throughput on the same 1.06 GiB file set, then captured each web UI. The rest of the page covers the 2025 fork that turned oCIS into OpenCloud, licensing, login and office options, client apps and the realistic migration paths off ownCloud. Every number below comes from those three lab VMs, run in October 2026, so you can compare them line by line.
OpenCloud vs Nextcloud vs ownCloud Infinite Scale: the short answer
For most self-hosters who want file sync and sharing and nothing else, we’d pick OpenCloud. It matched oCIS on footprint, stored files as plain files with their real names, and comes from the team that built oCIS. Nextcloud is still the one to choose when you want a whole groupware suite on one login:
- You want a lean file server for a family or small team: OpenCloud. One container, about 75 MiB of RAM at idle, no database to back up or upgrade.
- You want calendars, contacts, chat, video calls and office docs in one place: Nextcloud. Nothing else here comes close on apps, and the extra RAM buys you that.
- You already pay ownCloud (Kiteworks) for support, or run ownCloud Classic: stay on ownCloud and plan the move to Infinite Scale, since Classic 10 reaches end of life in January 2027.
- You run ownCloud Classic and want out of the ownCloud ecosystem: Nextcloud has a documented in-place migration from Classic 10.13 to 10.16; OpenCloud only offers a copy with rclone.
The decision table at the end maps more situations to a pick. If you are weighing Nextcloud against sync-only tools like Seafile or Syncthing instead, our Nextcloud vs ownCloud vs Seafile vs Syncthing comparison covers that question, and our Cloudreve vs Nextcloud, Seafile, File Browser and Immich test looks at the lighter web file managers. This page is about which full server platform to build on.
Benchmark results at a glance
Times are the median of six runs per server, taken as two sets of three about an hour apart. Every run moved the same 1,000 small files and four large ones over WebDAV, with rclone running on the server itself, so your network never enters these numbers.
| Measured | OpenCloud | ownCloud Infinite Scale | Nextcloud |
|---|---|---|---|
| Version tested | 8.1.0 (rolling) | 8.2.2 | 35.0.2 |
| Containers | 1 | 1 | 4 (app, cron, MariaDB, Redis) |
| Images on disk | 304 MB | 331 MB | 2.76 GB |
| Idle RAM, empty server | 75 MiB | 67 MiB | 244 MiB |
| Idle RAM after the benchmark | 245 MiB | 307 MiB | 444 MiB |
| Idle CPU, empty server | 1.1% | 0.6% | 0.2% |
| Peak RAM sampled during the first set | 743 MiB | 864 MiB | 685 MiB |
| Upload 1,000 x 64 KiB files | 168 s | 244 s | 511 s |
| Upload 4 x 256 MiB files | 10.2 s | 6.6 s | 10.5 s |
| Check 1,004 files, no changes | 0.95 s | 1.17 s | 3.31 s |
| Download 1,000 small files | 35.0 s | 38.6 s | 126.8 s |
| Download 4 large files | 6.9 s | 5.6 s | 5.3 s |
Nextcloud costs about three times the idle memory of either Go server and needs eight to nine times the image disk, and that is before you add an office suite. The surprise is idle CPU. Nextcloud sat at 0.2% between cron runs, while OpenCloud averaged 1.1% and oCIS 0.6%. That is most likely the embedded NATS event bus and the other internal services waking up, though we didn’t trace it. On a 4-core VM none of that matters. If you plan to run on a Raspberry Pi class box, though, the Go servers’ memory advantage is the number you should care about.
Small files are where the designs separate. OpenCloud took 168 seconds for the 1,000-file upload against 511 for Nextcloud. Every PUT into Nextcloud runs through PHP and also updates its file cache in MariaDB and a lock in Redis, and you pay that per file. oCIS landed in between at 244 seconds. Its slowest run took more than twice as long as its fastest, 138 to 300 seconds across six runs, and it was the only one that needed retries. Large files tell a different story. All three moved 1 GiB in roughly 5 to 11 seconds. oCIS had the best upload median even though two of its six large-file uploads needed a retry, and Nextcloud had the best download median. A gap of a few seconds per gigabyte is real but small, so you shouldn’t pick a server on that row alone.
The two sets didn’t agree, and the drift is worth knowing about. Between the first and second set, OpenCloud’s small-file upload median went from 208 to 159 seconds, while oCIS went from 157 to 287 and Nextcloud from 374 to 587. All three still held the first set’s deleted copies, about 2.3 GB each (OpenCloud’s .Trash, oCIS’s leftover blobs and Nextcloud’s trash bin), and Nextcloud’s file cache had grown to match. We didn’t isolate the cause, and OpenCloud got faster with the same amount of trash, so treat it as a warning sign rather than a rule. If you run oCIS or Nextcloud with heavy churn, it is worth watching small-file performance as deleted data piles up and emptying the trash on a schedule.
How we tested the three servers
Each server got its own Proxmox VM cloned from the same Ubuntu 26.04 template, so the hardware, kernel and Docker build were identical. We used each project’s smallest documented Docker deployment without a reverse proxy, because a proxy adds the same overhead to all three and hides the difference you’re here to see:
- VM spec: 4 vCPU (host CPU type), 8 GB RAM, 20 GB virtio disk on ZFS, Ubuntu 26.04 LTS with kernel 7.0.
- Runtime: Docker Engine 29.9.2 and Compose v5.6.1 from Docker’s own
resoluterepository. - Idle numbers: twelve
docker statssamples ten seconds apart, taken after the empty stack sat untouched for ten minutes and again five minutes after the benchmark. RAM is the median of the container sum, CPU the mean. - Peak RAM: the highest container sum in
docker statssamples taken every 15 seconds during the first set of three runs (the Nextcloud sampler was restarted once and lost at most one sample). - Throughput: the same script on every VM uploads 1,000 files of 64 KiB and four files of 256 MiB, checks them, downloads both sets, purges and repeats.
- Client: Ubuntu’s packaged rclone 1.60.1, which sends one plain PUT per file to all three servers, with no chunking or TUS on either side.
That last point keeps the comparison fair, but it is also a limit. The official desktop clients chunk large uploads and keep many connections open, so your sync speed will differ from ours. Read the throughput rows as a server-side processing comparison, not a promise about your LAN. Docker came from the same steps as our Docker CE install on Ubuntu 26.04.
The idle sampler is a loop around one command. Below are the call and a real sample from the Nextcloud VM, which shows how the four containers split the memory:
docker stats --no-stream --format '{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}'
MariaDB and the Apache/PHP app container carry almost all of Nextcloud’s idle memory, while Redis and the cron container barely register. Our lab project directory was called nc, which is where the container name prefix comes from.
nc-cron-1 0.00% 996KiB / 7.75GiB
nc-app-1 0.01% 109.4MiB / 7.75GiB
nc-redis-1 0.17% 5.789MiB / 7.75GiB
nc-db-1 0.01% 127.3MiB / 7.75GiB
Raw logs for every number on this page (timings, idle samples, under-load samples and disk usage) were kept per VM, and the medians and peaks in the table come straight from them. If you repeat the test, run it on your own hardware, because your disks and filesystem shape the large-file rows far more than the application does.
Architecture: Go services with no database vs PHP, MariaDB and Redis
OpenCloud and ownCloud Infinite Scale are the same design because OpenCloud started as a fork of oCIS. One Go binary starts about 34 internal services (proxy, web, identity provider, Graph API, storage, search, NATS for events) and keeps user data, metadata, the search index and the user directory on the filesystem. Nextcloud keeps files on disk too, but every file’s metadata, every share and every user lives in its database, and Redis handles file locking. The diagram shows the two shapes side by side.

We counted the services from inside the running OpenCloud container, and ocis list on the oCIS VM returned the same count of 34, with one difference: oCIS lists an ocdav service where OpenCloud lists auth-app. You can list them yourself on a running server.
docker exec opencloud opencloud list
All of these run as goroutines in one process, so there’s one container to restart, one log stream and one image to update.
┌────────────────────┐
│ SERVICE │
├────────────────────┤
│ activitylog │
│ app-provider │
│ app-registry │
│ auth-app │
│ auth-basic │
│ auth-machine │
│ auth-service │
│ clientlog │
│ eventhistory │
│ frontend │
│ gateway │
│ graph │
│ groups │
│ idm │
│ idp │
│ nats │
│ ocm │
│ ocs │
│ postprocessing │
│ proxy │
│ search │
│ settings │
│ sharing │
│ sse │
│ storage-publiclink │
│ storage-shares │
│ storage-system │
│ storage-users │
│ thumbnails │
│ userlog │
│ users │
│ web │
│ webdav │
│ webfinger │
└────────────────────┘
The flip side is less isolation, since every service shares one process and one container memory limit, and you tune them through environment variables rather than a config file per daemon. For a small server that trade is worth it, because there is no database to size and no PHP worker pool to tune.
OpenCloud vs ownCloud Infinite Scale: how files sit on disk
The two Go servers have drifted apart in one place that matters for backups. A fresh OpenCloud install uses the PosixFS storage driver. Your files land on disk under their real names, and OpenCloud keeps its metadata in extended attributes. oCIS still uses DecomposedFS, which stores content as UUID-named blobs and keeps names in MessagePack files and symlinks. Listing an upload on the OpenCloud VM shows ordinary files. The path ends in our benchmark folder, bench/large, so substitute any folder you’ve uploaded on your own server:
sudo ls -l ~/opencloud/data/storage/users/users/*/bench/large/
The four test files are there under their own names and at their full 268,435,456-byte size, inside a directory named after the user’s UUID:
total 1048604
-rw-r--r--+ 1 valentine valentine 268435456 Oct 26 21:23 big1.bin
-rw-r--r--+ 1 valentine valentine 268435456 Oct 26 21:23 big2.bin
-rw-r--r--+ 1 valentine valentine 268435456 Oct 26 21:23 big3.bin
-rw-r--r--+ 1 valentine valentine 268435456 Oct 26 21:23 big4.bin
OpenCloud’s own bookkeeping rides along in user.oc.* extended attributes, which getfattr (from the attr package) prints:
sudo getfattr -d ~/opencloud/data/storage/users/users/*/bench/large/big1.bin
Each file carries its ID, parent ID, size, modification time and three checksums:
# file: home/valentine/opencloud/data/storage/users/users/819c42a4-2830-4ecf-8263-b52e0b07f45e/bench/large/big1.bin
user.oc.blobid="5ca357b3-bd24-4da2-b9ab-692011b7ac92"
user.oc.blobsize="268435456"
user.oc.cs.adler32=0sB0MjSg==
user.oc.cs.md5=0sgXHZJh7rKX/Omd/hx0fOmw==
user.oc.cs.sha1=0saPQnHY/6GAYyHqifs0JGJ65aDLA=
user.oc.id="e2507fae-101b-4773-875d-3e74e5594008"
user.oc.mtime="2026-10-26T21:23:36Z"
user.oc.name="big1.bin"
user.oc.parentid="8b744d2f-164c-4df9-99fa-b4f838932003"
user.oc.type="1"
That has two consequences. A plain rsync or restic run on the data directory gives you a backup you can browse without OpenCloud. That backup must keep extended attributes and the ACLs OpenCloud sets (rsync -aAX), and the target filesystem has to support them too. OpenCloud’s requirements page asks for a POSIX filesystem with xattrs, and NFS only from 4.2 with the noac mount option.
On the oCIS VM, the same file name only exists as a symlink. Searching for it shows every copy the benchmark ever uploaded, because DecomposedFS keeps the nodes of deleted files until the trash is emptied:
sudo find ~/ocis/data/storage/users/spaces -name big1.bin -exec ls -l {} \;
Six symlinks for one live file, each pointing to a node directory named by UUID fragments:
lrwxrwxrwx 1 valentine valentine 55 Oct 26 22:36 /home/valentine/ocis/data/storage/users/spaces/47/ffbbe0-e7b2-4875-80e4-1e814e8cac80/nodes/62/54/15/74/-c67d-48bf-ac37-23596aca5608/big1.bin -> ../../../../../a9/6c/79/e2/-0bd5-435d-a08e-2c24a5455031
lrwxrwxrwx 1 valentine valentine 55 Oct 26 21:14 /home/valentine/ocis/data/storage/users/spaces/47/ffbbe0-e7b2-4875-80e4-1e814e8cac80/nodes/39/5f/0d/ae/-310d-4e03-b585-fced01a4be8f/big1.bin -> ../../../../../94/a4/bb/1c/-af85-4c8f-84ea-8fc787205611
lrwxrwxrwx 1 valentine valentine 55 Oct 26 22:30 /home/valentine/ocis/data/storage/users/spaces/47/ffbbe0-e7b2-4875-80e4-1e814e8cac80/nodes/91/30/b6/db/-ee58-43a2-ae61-84c8430d7144/big1.bin -> ../../../../../ce/d2/85/5e/-1e3e-4428-8ce1-c1e3d12eff95
lrwxrwxrwx 1 valentine valentine 55 Oct 26 22:24 /home/valentine/ocis/data/storage/users/spaces/47/ffbbe0-e7b2-4875-80e4-1e814e8cac80/nodes/03/41/16/b2/-9b1f-4b24-9e5c-d4b6bdb443da/big1.bin -> ../../../../../fb/0f/12/19/-0dea-4461-8327-4185c2f92981
lrwxrwxrwx 1 valentine valentine 55 Oct 26 21:22 /home/valentine/ocis/data/storage/users/spaces/47/ffbbe0-e7b2-4875-80e4-1e814e8cac80/nodes/1a/af/24/81/-026d-48e3-8567-4172064a8324/big1.bin -> ../../../../../bf/bc/62/3f/-30e0-460c-83de-53982c6fa81a
lrwxrwxrwx 1 valentine valentine 55 Oct 26 21:17 /home/valentine/ocis/data/storage/users/spaces/47/ffbbe0-e7b2-4875-80e4-1e814e8cac80/nodes/6e/30/ef/5d/-f7f5-41ad-b80c-f28ec8df4bea/big1.bin -> ../../../../../48/6d/c3/68/-ed40-48ab-98d2-fd1767bd8e9d
Following the first link that find returns lands on an empty node file plus a lock file and a 377-byte MessagePack file that holds the name, size, checksums and the ID of the blob with the actual data:
sudo ls -l $(sudo find ~/ocis/data/storage/users/spaces -name big1.bin | head -1 | xargs sudo readlink -f)*
None of the three files contains your data, which is the point of the design:
-rw------- 1 valentine valentine 0 Oct 26 22:36 /home/valentine/ocis/data/storage/users/spaces/47/ffbbe0-e7b2-4875-80e4-1e814e8cac80/nodes/a9/6c/79/e2/-0bd5-435d-a08e-2c24a5455031
-rw------- 1 valentine valentine 0 Oct 26 22:36 /home/valentine/ocis/data/storage/users/spaces/47/ffbbe0-e7b2-4875-80e4-1e814e8cac80/nodes/a9/6c/79/e2/-0bd5-435d-a08e-2c24a5455031.mlock
-rw------- 1 valentine valentine 377 Oct 26 22:36 /home/valentine/ocis/data/storage/users/spaces/47/ffbbe0-e7b2-4875-80e4-1e814e8cac80/nodes/a9/6c/79/e2/-0bd5-435d-a08e-2c24a5455031.mpk
The 256 MiB of content sits in a separate blobs/ tree under another UUID path, with no extended attributes at all. That layout lets oCIS rename and move files cheaply. The cost is that a backup of the data directory is useless without oCIS to read it, and you can’t open a user’s folder on the host and find their files. Disk use after the benchmark says more about trash than about layout. After the first set of three runs, all three servers held about 3.5 GB of data for 1.06 GiB of live files, because the copies rclone purged between runs were still on disk.
There is no conversion from DecomposedFS to PosixFS, according to OpenCloud’s storage documentation, and PosixFS has been the default only since OpenCloud 2.0.0, so a server that started life before that keeps the decomposed layout. Nextcloud sits closer to OpenCloud here. Its files are plain files under data/<user>/files/, but the database is the source of truth for metadata, so a file you copy in by hand stays invisible until occ files:scan runs.
1. OpenCloud
OpenCloud wins on footprint and on how simply your data is stored, and it is the one we’d put on a home server or a small office box. The Berlin-based Heinlein Group announced OpenCloud GmbH in January 2025 with a team of former ownCloud developers. Their fork of oCIS shipped its 1.0 release in February 2025. Kiteworks, which owns ownCloud, told heise at the time that it intended to sue, and we found no public outcome of that.
OpenCloud publishes three release types: rolling releases about every three weeks, production releases about every six months, and paid LTS releases. The opencloudeu/opencloud-rolling image carried the 8.1 rolling release when we tested, while the production image opencloudeu/opencloud was still on the 7.2 line. We tested rolling because the docs quick start and the official compose project both default to it. A production server that wants fewer upgrades should pin the production image instead, which you can check on the OpenCloud releases page.
Start by creating the two directories the container mounts. The image runs as UID 1000, so the directories must belong to that user, or opencloud init can’t write its config and the server never starts:
mkdir -p ~/opencloud/config ~/opencloud/data
On our VM the login user was UID 1000 already. If yours isn’t (check with id -u), hand the directories over with sudo chown -R 1000:1000 ~/opencloud. Then create the compose file, which is the exact file we ran with the lab IP swapped for a documentation address:
vim ~/opencloud/compose.yaml
Change OC_URL to the address your users will type and pick your own admin password. PROXY_ENABLE_BASIC_AUTH is only there so rclone could log in for the benchmark, and OpenCloud warns at startup that it is meant for testing, so delete that line on a real server:
services:
opencloud:
image: opencloudeu/opencloud-rolling:8.1.0
container_name: opencloud
entrypoint: ["/bin/sh", "-c", "opencloud init || true; opencloud server"]
ports:
- "9200:9200"
volumes:
- ./config:/etc/opencloud
- ./data:/var/lib/opencloud
environment:
OC_URL: https://10.0.1.51:9200
OC_INSECURE: "true"
PROXY_HTTP_ADDR: 0.0.0.0:9200
PROXY_ENABLE_BASIC_AUTH: "true"
OC_LOG_LEVEL: info
IDM_ADMIN_PASSWORD: Bench-Admin-2026
restart: unless-stopped
Start it and ask the status endpoint what is running. With the image already pulled, the first healthy answer came back 4.2 seconds after up, so give it a few seconds before the curl:
cd ~/opencloud && docker compose up -d
curl -sk https://localhost:9200/status.php
The productversion field is the one to read, and edition tells you which channel you’re on:
{
"installed": true,
"maintenance": false,
"needsDbUpgrade": false,
"version": "0.1.0.0",
"versionstring": "0.1.0",
"edition": "rolling",
"productname": "OpenCloud",
"product": "OpenCloud",
"productversion": "8.1.0",
"channel": ""
}
During the first second of boot, the proxy logged the same pair of errors on two status polls while the web service was still registering. They cleared on their own, but they look alarming if you tail the log during a restart:
{"level":"error","service":"proxy","error":"not found","service":"eu.opencloud.web.frontend","time":"2026-10-26T21:09:48Z","line":"github.com/opencloud-eu/opencloud/services/proxy/pkg/router/router.go:162","message":"could not select service from the registry"}
{"level":"error","service":"proxy","remoteAddr":"172.18.0.1:56616","request-id":"","proto":"HTTP/2.0","method":"GET","path":"/status.php","query":"","fragment":"","error":"unsupported protocol scheme \"\"","time":"2026-10-26T21:09:48Z","line":"github.com/opencloud-eu/opencloud/services/proxy/pkg/proxy/proxy.go:59","message":"error happened in MultiHostReverseProxy"}
The web UI is the same Vue application oCIS uses, restyled. Logged in as the admin, the folder holding the four 256 MiB test files looked like this, with the version shown in the bottom left:

If you need office editing, know that it is not built in. OpenCloud’s collaboration service speaks WOPI to Collabora Online, ONLYOFFICE or Microsoft’s online Office, and each of those runs as its own container. Without one, the New menu on our single container offered only folders, uploads, notes, Markdown files and shortcuts:

If you want office documents, plan for that extra container and its RAM from the start. Our guide to deploying Collabora Online with Let’s Encrypt covers the server half. Sign-in uses the bundled LibreGraph Connect identity provider by default, and the docs describe switching to Keycloak or another OpenID Connect provider by disabling the idp service.
Where OpenCloud falls short is maturity and reach rather than the core, so weigh these before you commit:
- Thin app ecosystem: a handful of web extensions against Nextcloud’s store, so anything beyond files means another product.
- No upgrade from ownCloud Classic: you copy data in with rclone and set shares up again.
- A fast rolling channel: 8.0 needed a full search reindex after the upgrade, so read every release note if you stay on rolling.
None of those hurt a family or small-team file server. Pick OpenCloud if you mainly need files, shares and spaces with good clients, and you want the lowest upkeep of the three.
2. ownCloud Infinite Scale (and ownCloud Classic)
ownCloud Infinite Scale is the safe pick if your organisation already has an ownCloud contract, and it had the best median for large uploads in our runs. ownCloud has been part of Kiteworks since a merger announced in November 2023. The developers who moved to Heinlein are the core of OpenCloud. The code is still Apache 2.0, and in May 2026 Kiteworks set up an open source program office for ownCloud that dropped the CLA in favour of a DCO.
Our oCIS compose file mirrors the OpenCloud one, which makes the comparison clean. Create its two directories first, for the same UID 1000 reason:
mkdir -p ~/ocis/config ~/ocis/data
Then open the compose file:
vim ~/ocis/compose.yaml
The image, the variable prefix and the paths change, and the oCIS file leaves out PROXY_HTTP_ADDR. The production image tag was current on the day we tested:
services:
ocis:
image: owncloud/ocis:8.2.2
container_name: ocis
restart: unless-stopped
entrypoint: ["/bin/sh", "-c", "ocis init || true; ocis server"]
ports:
- "9200:9200"
volumes:
- ./config:/etc/ocis
- ./data:/var/lib/ocis
environment:
OCIS_URL: https://10.0.1.52:9200
OCIS_INSECURE: "true"
PROXY_ENABLE_BASIC_AUTH: "true"
OCIS_LOG_LEVEL: info
IDM_ADMIN_PASSWORD: Bench-Admin-2026
Start it with cd ~/ocis && docker compose up -d. The status endpoint confirms the product and still reports a version string inherited from ownCloud 10, which is why clients that check versionstring see 10.11.0:
curl -sk https://localhost:9200/status.php
It reported Infinite Scale 8.2.2, Community edition:
{
"installed": true,
"maintenance": false,
"needsDbUpgrade": false,
"version": "10.11.0.0",
"versionstring": "10.11.0",
"edition": "Community",
"productname": "Infinite Scale",
"product": "Infinite Scale",
"productversion": "8.2.2"
}
oCIS was the only server that threw errors during the benchmark, and it did so in all six runs. The first set logged 157 failed uploads and the second 240, five of them 256 MiB files. Every one succeeded on rclone’s automatic second attempt, and every rclone check --size-only afterwards found all 1,004 files present at the right size. The errors all read the same:
2026/10/26 21:11:56 ERROR : dir04/file015.bin: Failed to copy: object not found
2026/10/26 21:11:56 ERROR : dir04/file016.bin: Failed to copy: object not found
2026/10/26 21:12:02 ERROR : dir04/file049.bin: Failed to copy: object not found
Our reading is that rclone looked the file up a moment before oCIS made it visible after the PUT, which the retry then papered over. The desktop client retries the same way, so you are unlikely to notice it, but you should know about it if you script uploads. The web UI shows the ownCloud branding and the “A Kiteworks Company” line on the login page:

Inside, the file list is the same application as OpenCloud’s with ownCloud’s colours, and the footer reports both the server and the web UI version:

ownCloud Classic, the PHP server most people mean when they say “ownCloud”, is still alive. Classic 11.0 shipped in July 2026 with PHP 8.3 as the minimum and supports Docker-based installs only. The 10.16 line still gets fixes, but ownCloud’s schedule puts the end of life for 10 in January 2027, and the company says it isn’t building major new features on the Classic codebase. Its official way forward is the migrate_to_ocis app, which moves users, groups, files and shares into Infinite Scale.
oCIS has real weak spots for a self-hoster without a contract, and most trace back to the 2025 split:
- A smaller community: many of its developers moved to OpenCloud, so forum answers and third-party guides now skew that way.
- Opaque storage: DecomposedFS blobs are harder to back up, inspect and restore by hand than OpenCloud’s plain files.
- Upload retries: the only server in our test that failed uploads on the first attempt, 397 times across six runs.
Pick oCIS when you want a vendor contract behind your file server, or when you’re on Classic and want the upgrade path ownCloud supports. If you have neither, OpenCloud gives you the same design with more momentum.
3. Nextcloud
Nextcloud is the one to pick when files are only part of what you need. Nextcloud 35 shipped in September 2026 as “Hub 26 Summer”, and the Hub brings Talk for chat and calls, groupware for mail, calendar and contacts, office integration through a separate document server, and hundreds of apps in its store. It is AGPL-3.0, so if you modify it and offer it to users over a network you have to publish your changes, which matters to companies that patch it.
We started from the insecure/mariadb/apache example in the official image’s repository, which already includes Redis and a cron container. Our copy differs in four ways: the db.env settings are inlined, the image is pinned to 35-apache, the NEXTCLOUD_ADMIN_* and NEXTCLOUD_TRUSTED_DOMAINS variables trigger an unattended install, and the port is published as 8080:80 instead of 127.0.0.1:8080:80. That last change exposes plain HTTP on every interface, so put a TLS reverse proxy in front or keep the localhost binding outside a lab. Create the project directory first:
mkdir -p ~/nextcloud
Then create the compose file:
vim ~/nextcloud/compose.yaml
Four services and two named volumes. Swap every password before you use it, and set NEXTCLOUD_TRUSTED_DOMAINS to your hostname:
services:
db:
image: mariadb:lts
command: --transaction-isolation=READ-COMMITTED
restart: always
volumes:
- db:/var/lib/mysql:Z
environment:
- MYSQL_ROOT_PASSWORD=Bench-Root-2026
- MARIADB_AUTO_UPGRADE=1
- MARIADB_DISABLE_UPGRADE_BACKUP=1
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=Bench-Db-2026
redis:
image: redis:alpine
restart: always
app:
image: nextcloud:35-apache
restart: always
ports:
- 8080:80
volumes:
- nextcloud:/var/www/html:z
environment:
- MYSQL_HOST=db
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=Bench-Db-2026
- REDIS_HOST=redis
- NEXTCLOUD_ADMIN_USER=admin
- NEXTCLOUD_ADMIN_PASSWORD=Bench-Admin-2026
- NEXTCLOUD_TRUSTED_DOMAINS=10.0.1.53 localhost
depends_on:
- db
- redis
cron:
image: nextcloud:35-apache
restart: always
volumes:
- nextcloud:/var/www/html:z
entrypoint: /cron.sh
depends_on:
- db
- redis
volumes:
db:
nextcloud:
Start the stack from the project directory. Compose prints a harmless warning three times, “mount of type volume should not define bind option”, because of the :z and :Z suffixes the upstream example uses:
cd ~/nextcloud && docker compose up -d
The first start runs the installer inside the app container, so wait until the status page reports "installed":true before you run any occ command:
curl -s http://localhost:8080/status.php
This is the answer to wait for:
{"installed":true,"maintenance":false,"needsDbUpgrade":false,"version":"35.0.2.2","versionstring":"35.0.2","edition":"","productname":"Nextcloud","extendedSupport":false}
Once it’s up, switch background jobs to the cron container and confirm the version. Using docker compose exec with the service name avoids guessing the container name, which Compose builds from the directory name:
docker compose exec -u www-data app php occ background:cron
docker compose exec -u www-data app php occ status
The image ran Nextcloud 35.0.2 on PHP 8.5, with MariaDB 12.3 and Redis 8.10 beside it:
Set mode for background jobs to 'cron'
- installed: true
- version: 35.0.2.2
- versionstring: 35.0.2
- edition:
- maintenance: false
- needsDbUpgrade: false
- productname: Nextcloud
- extendedSupport: false
Then run Nextcloud’s own health check, which is where its extra moving parts show up:
docker compose exec -u www-data app php occ setupchecks
On our fresh install cron passed, but four warnings remained. This excerpt shows only the warning lines, not the passing checks and info items around them:
⚠ Maintenance window start: Server has no maintenance window start time configured. This means resource intensive daily background jobs will also be executed during your main usage time. We recommend to set it to a time of low usage, so users are less impacted by the load caused from these heavy tasks.
⚠ Mimetype migrations available: One or more mimetype migrations are available. Occasionally new mimetypes are added to better handle certain file types. Migrating the mimetypes take a long time on larger instances so this is not done automatically during upgrades. Use the command `occ maintenance:repair --include-expensive` to perform the migrations.
⚠ Database configuration: 1 database check is failing. Show the findings…
⚠ HTTP headers: Some headers are not set correctly on your instance
None of these stop Nextcloud working, but each is a task OpenCloud and oCIS don’t have, and a production Nextcloud collects more of them over time. The database also grows with your data. After our first set of runs, oc_filecache held 3,136 rows for the 1,004 live test files plus the trash bin and app data, and every file you add is another row MariaDB has to keep fast. Our Nextcloud install guide for Ubuntu 26.04 is the place to start if you’d rather run it without containers.
The Files app itself is familiar to anyone who has used Nextcloud in the last few years. Here are the same four test files after the benchmark:

The app store is the reason most people put up with the extra containers. Categories run from AI and dashboards to games, monitoring, multimedia and office, and each one installs into the same PHP application with a click:

Office in Nextcloud 35 changed hands. The admin manual now lists Nextcloud Office “powered by Euro-Office” as the default office solution, which needs a Euro-Office Document Server, and keeps Collabora Online as a fully supported alternative. Unless you use Collabora’s built-in app, which runs inside Nextcloud for small setups, it is one more server to run, but it plugs into the same login, sharing and Talk calls, which no OpenCloud or oCIS setup matches today.
Nextcloud’s costs are the flip side of its breadth, and you’ll feel them most on small hardware:
- Slowest on small files: about three times OpenCloud’s time for the 1,000-file upload and over three times for the download in our runs.
- Heaviest footprint: four containers, about 244 MiB idle, and a 2.13 GB app image before any office server.
- Stepwise upgrades: one major version at a time, each with database migrations and apps that must keep up.
Pick Nextcloud when your users want one place for files, chat, calendars and documents. You’re taking on a PHP stack to get that, and it’s a fair trade when the extra apps replace other services you’d otherwise run.
Desktop and mobile clients
All three have their own sync client on every desktop OS and apps for both phone platforms, so client support no longer decides this. The table lists the latest releases on each project’s GitHub when we checked:
| Client | OpenCloud | ownCloud Infinite Scale | Nextcloud |
|---|---|---|---|
| Desktop (latest) | 4.0.0, September 2026 | 7.1.1, September 2026 | 35.0.0, October 2026 |
| Desktop platforms | Linux AppImage and macOS (Apple silicon, Intel) on GitHub; Windows from the Microsoft Store | Windows MSI, macOS pkg, Linux AppImage, deb and rpm | Windows, macOS, Linux |
| Android | 1.2.0, Google Play and F-Droid | 4.8.4 (also works with Classic) | 35.0.1, Google Play and F-Droid |
| iOS | App Store | 12.7.1, App Store | 35.2.1, App Store |
Two details in that table catch people out. ownCloud’s own docs say that from desktop 7.0 the client supports only Infinite Scale, so anyone still on ownCloud Classic has to stay on the 6.x desktop line or move servers. OpenCloud doesn’t publish a Windows installer on GitHub and points Windows users to the Microsoft Store, which matters on locked-down company laptops where the store is blocked.
Licensing, sign-in and office suites compared
The licence split is simple: OpenCloud and oCIS servers are Apache 2.0, while Nextcloud and ownCloud Classic are AGPL-3.0. For a home lab that changes nothing. For a company that modifies the server and lets outside users reach it, AGPL means publishing those changes, while Apache 2.0 doesn’t ask for that.
| OpenCloud | ownCloud Infinite Scale | Nextcloud | |
|---|---|---|---|
| Server licence | Apache 2.0 | Apache 2.0 | AGPL-3.0 |
| Language | Go | Go | PHP |
| Database | None | None | MariaDB, MySQL or PostgreSQL |
| Default storage | PosixFS: real file names, metadata in xattrs | DecomposedFS: UUID blobs, MessagePack metadata | Plain files, metadata in the database |
| Built-in sign-in | LibreGraph Connect IdP with built-in LDAP (idm) | Built-in IdP with built-in LDAP (idm) | Local users in the database, LDAP app |
| External OIDC | Keycloak or any OIDC provider | Keycloak or any OIDC provider | user_oidc app |
| Browser office | Collabora, ONLYOFFICE or Microsoft via WOPI | Collabora, ONLYOFFICE or Microsoft via WOPI | Nextcloud Office (Euro-Office), Collabora, ONLYOFFICE |
| Release rhythm | Rolling about every 3 weeks, production about every 6 months, paid LTS | Rolling about every 3 weeks, production about every 6 months | About three majors a year (33, 34 and 35 in 2026) |
| Company | OpenCloud GmbH (Heinlein Group) | Kiteworks | Nextcloud GmbH |
If your organisation already runs an identity provider, all three can use it, so that isn’t a deciding factor either. Our Keycloak vs Authentik vs Zitadel vs Authelia comparison helps if you are choosing one to put in front of whichever server you pick. Office is where they differ. Nextcloud can run Collabora’s built-in app with no extra server and integrates ONLYOFFICE as well (see our guide to connecting ONLYOFFICE Docs to Nextcloud), while OpenCloud and oCIS always need a separate office server.
Upgrade path and migration from ownCloud
Moving between these servers is easiest from ownCloud Classic to Nextcloud, because Nextcloud started as a fork of it and still reads its database. Everything else is a data copy rather than an upgrade:
- ownCloud Classic 10 to Nextcloud: in place. Nextcloud’s migration guide maps ownCloud 10.13 through 10.16 to Nextcloud 34.0.0, and lists the
occ db:repair commands to run after that upgrade. From 34 you move to 35 with a normal one-major upgrade. Classic 11 isn’t in its table yet. - ownCloud Classic to Infinite Scale: the
migrate_to_ocisapp, which you get from ownCloud support, moves users, groups, files and shares withocc migrate:to-ociscommands. Roles, passwords, external mounts and subadmin rights don’t carry over. - oCIS or Nextcloud to OpenCloud: OpenCloud’s docs describe copying each user’s personal space with rclone using app tokens. Shares, public links, project spaces, trash and file versions are not migrated, and we found no in-place path even from oCIS.
- ownCloud Classic to OpenCloud: no tool. OpenCloud publishes a migration whitepaper, but the practical route is the same rclone copy, or Classic to oCIS first.
One snag in OpenCloud’s rclone example is that it sets vendor = opencloud, a value that isn’t in rclone’s list of WebDAV vendors (we checked the current rclone source). rclone accepts it silently and applies no vendor-specific handling, so file modification times aren’t carried over. The infinitescale vendor is the closer match for an oCIS-derived server, but it only exists in recent rclone releases from rclone.org, not in the 1.60.1 build Ubuntu ships. Test with one small user first and compare file counts before you move everyone. Nextcloud’s ownCloud migration guide has the exact version table if you are on Classic today.
Upgrades within each product differ as much. OpenCloud and oCIS upgrades are an image tag change plus whatever the release notes ask for, such as OpenCloud 8.0’s search reindex. Nextcloud upgrades run database migrations and can’t skip a major version, so a server two majors behind needs two upgrades in a row, and apps can hold an upgrade back until their authors catch up.
Which one to pick: OpenCloud, ownCloud or Nextcloud
Match the server to the job you need it to do, not to the longest feature list. Each pick below is tied to something we measured or a fact you can check:
| Your situation | Pick | Why |
|---|---|---|
| Home or family file server on a small box | OpenCloud | One container, about 75 MiB idle in our lab, plain files on disk you can back up with rsync |
| Small team that wants files plus calendars, contacts, chat and calls | Nextcloud | Talk, groupware and an office suite behind one login; costs 4 containers and about 244 MiB idle |
| Running ownCloud Classic 10 with a support contract | ownCloud Infinite Scale | migrate_to_ocis moves users and shares; Classic 10 reaches end of life in January 2027 |
| Running ownCloud Classic and leaving the ownCloud ecosystem | Nextcloud | The only documented in-place migration (from 10.13 to 10.16) |
| Running oCIS and want the developers who built it | OpenCloud | Same design and services; plan an rclone copy, not an upgrade |
| You modify the server and offer it to outside users | OpenCloud or oCIS | Apache 2.0 has no duty to publish your changes; AGPL-3.0 does |
| You need hundreds of plugins and integrations | Nextcloud | The app store has no equal on the other two |
| You want backups readable without the app | OpenCloud | PosixFS keeps real names; oCIS stores UUID blobs |
| Strict uptime with as few moving parts as possible | OpenCloud or oCIS | No database or Redis to patch, tune or fail over |
For a fresh self-hosted file server in 2026, we’d start with OpenCloud on its production image. Add Collabora only if your people really edit documents in the browser, and put Keycloak in front once you have more than one app to log into. If your team lives in shared calendars and chat as much as in folders, Nextcloud remains the better platform, and it is worth every extra megabyte it uses.