Home Lab Part 3: OpenCloud — Replacing Google Drive and Nextcloud

April 3, 2026 — #home-lab #opencloud #docker #self-hosting #collabora

After Immich for photos, the next thing to self-host was file sync and office editing. I started with Nextcloud but quickly switched to OpenCloud — a Go-based alternative that’s lighter, faster, and doesn’t need a database.

Why OpenCloud over Nextcloud

OpenCloudNextcloud
LanguageGoPHP
RAM idle~100 MB1–2 GB
DatabaseNone (metadata in filesystem)PostgreSQL/MySQL required
BackupZFS snapshot = full atomic backupDB dump + files separately
Collabora latencyLower (Go WOPI)Higher

The biggest win: no database. All metadata lives in the filesystem alongside the files. A ZFS snapshot gives you a complete, consistent backup — no need to coordinate DB dumps with file backups.

OpenCloud file browser

Architecture

Four containers work together:

ContainerPortPurpose
opencloud9200Main server (files, sharing, auth)
opencloud_collaboration9300WOPI server (Collabora bridge)
collabora9980Collabora Online (document editing)
radicale5232CalDAV/CardDAV (calendar & contacts)

Docker Compose

The key config decisions:

services:
  opencloud:
    image: owncloud/opencloud-rolling:latest
    entrypoint: ["/bin/sh"]
    command: ["-c", "opencloud init || true; opencloud server"]
    user: "1000:1000"
    volumes:
      - /mnt/nextcloud:/var/lib/opencloud
      - ./oc-config:/etc/opencloud
    environment:
      PROXY_TLS: "false"
      PROXY_ENABLE_BASIC_AUTH: "true"
    networks:
      - proxy
      - internal
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.opencloud.rule=Host(`cloud.johannes-kling.de`)"
      - "traefik.http.services.opencloud.loadbalancer.server.port=9200"
      - "traefik.http.middlewares.opencloud-headers.headers.customrequestheaders.X-Forwarded-Proto=https"

A few things to note:

The || true in the entrypoint is critical. opencloud init creates the initial config but fails on subsequent starts because the config already exists. Without || true, the container crashes on every restart.

PROXY_ENABLE_BASIC_AUTH: "true" is required for WebDAV clients (like desktop sync or mobile apps) to authenticate. Without it, only browser-based OAuth login works.

X-Forwarded-Proto=https middleware — since Traefik serves HTTP internally and Cloudflare handles TLS, OpenCloud thinks it’s running on HTTP and creates redirect loops. This header tells it the client connection is actually HTTPS.

Run as non-root with user: "1000:1000". All data directories must be owned by this uid/gid.

Collabora Online

Collabora Online editing a document

Collabora gives you in-browser editing of documents, spreadsheets, and presentations — like Google Docs but self-hosted. OpenCloud connects to it via a WOPI server.

The critical environment variables that aren’t obvious:

environment:
  NATS_NATS_HOST: 0.0.0.0
  GATEWAY_GRPC_ADDR: 0.0.0.0:9142

Without binding NATS and gRPC to 0.0.0.0, Collabora can’t communicate with OpenCloud across Docker containers (they default to localhost).

CalDAV/CardDAV with Radicale

Radicale handles calendar and contacts sync. OpenCloud proxies the requests internally — no separate subdomain needed.

# config/opencloud/proxy.yaml — routes DAV traffic to Radicale

Auth is handled via http_x_remote_user — OpenCloud passes the logged-in user to Radicale via header, so there are no separate credentials to manage.

To connect a phone: point DAVx5 (Android, free on F-Droid) or iOS Calendar/Contacts at https://cloud.johannes-kling.de. It auto-discovers the CalDAV/CardDAV endpoints.

Config Files

OpenCloud needs a few config files from the opencloud-compose repo:

  • csp.yaml — Content Security Policy headers
  • banned-password-list.txt — password blacklist
  • proxy.yaml — routes /caldav/ and /carddav/ to Radicale

Gotchas

All data directories must be owned by uid/gid 1000:1000. If permissions are wrong, OpenCloud starts but silently fails to write files.

Collabora needs NATS + gRPC bound to 0.0.0.0. The default localhost binding doesn’t work across Docker containers.

The X-Forwarded-Proto header is non-negotiable. Without it, you get an infinite redirect loop between HTTP and HTTPS.

Backup

This is where OpenCloud really shines over Nextcloud. Since there’s no database — all state lives in the filesystem — a single ZFS snapshot is a complete, atomic backup:

zfs snapshot hdd-01/data/nextcloud@backup-$(date +%F)

No DB dumps, no coordination, no risk of inconsistency.

Result

OpenCloud is live at cloud.johannes-kling.de — file sync, document editing, and calendar/contacts all in one place. It uses a fraction of the resources Nextcloud needed and backup is trivially simple.

Next up: MCP Servers — giving AI assistants access to a shared knowledge base.