Skip to content

CRD Overview

Custom Resource Definitions

The Nextcloud Operator provides the following CRDs:

  • Nextcloud (nc) — Tenant-facing logical resource (namespaced)
  • NextcloudInstance (nci) — Physical Nextcloud instance resource (namespaced)
  • NextcloudPool (ncp) — Pre-provisioned instance pool management (cluster-scoped)
  • NextcloudProfile (ncprofile) — Reusable configuration profiles (cluster-scoped)
  • NextcloudVersionMap (ncvm) — Version-to-chart mapping and default images (cluster-scoped)
  • SignalingServer (ss) — HPB signaling server backend registration (cluster-scoped)
  • RecordingServer (rs) — Talk recording server backend registration (cluster-scoped)
  • NextcloudCommand (nccmd) — Ad-hoc occ command runner (namespaced). See the Commands guide.

API Version: k8s.bnerd.com/v1alpha1

For the full interactive API specification, see the OpenAPI / Swagger page.

API Resources

NextcloudInstance Resource

Minimal Example

apiVersion: k8s.bnerd.com/v1alpha1
kind: NextcloudInstance
metadata:
  name: my-nextcloud
  namespace: default
spec:
  profile: production
  ingress:
    host: cloud.example.com

Complete Example

apiVersion: k8s.bnerd.com/v1alpha1
kind: NextcloudInstance
metadata:
  name: production-nextcloud
  namespace: nextcloud
  labels:
    environment: production
spec:
  profile: production
  version: "29"
  replicas: 3

  ingress:
    enabled: true
    host: cloud.company.com
    className: nginx
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
    tls:
      enabled: true

  database:
    type: postgresql
    managed: true
    postgres:
      replicas: 3
      storage:
        size: 50Gi
      backup:
        enabled: true
        s3:
          bucket: pg-backups
          endpoint: s3.example.com
          credentialsSecret: backup-s3-creds

  redis:
    enabled: true
    credentialsSecret: nextcloud-redis-creds

  s3:
    enabled: true
    credentialsSecret: nextcloud-s3-creds

  backups:
    data:
      enabled: true
      bucket: nextcloud-backups
      endpoint: s3.example.com
      region: eu-central-1
      credentialsSecret: nextcloud-backup-creds
      schedule: "0 3 * * *"
      deleteOnCleanup: false

  admin:
    credentialsSecret: nextcloud-admin-creds

  mail:
    enabled: true
    credentialsSecret: nextcloud-mail-creds

  resources:
    requests:
      cpu: 1000m
      memory: 2Gi
    limits:
      cpu: 4000m
      memory: 8Gi

  persistence:
    enabled: true
    size: 100Gi
    storageClass: fast-ssd

NextcloudProfile Resource

apiVersion: k8s.bnerd.com/v1alpha1
kind: NextcloudProfile
metadata:
  name: high-performance
spec:
  description: High-performance profile for production workloads
  defaults:
    version: "stable"        # Pins NC version for instances using this profile
    replicaCount: 3
    resources:
      requests:
        cpu: 2000m
        memory: 4Gi
      limits:
        cpu: 8000m
        memory: 16Gi
    persistence:
      enabled: true
      size: 200Gi
      storageClass: fast-ssd
    internalDatabase:
      enabled: false
  helm:
    version: "5.0.0"          # Helm chart version (escape hatch)

spec.defaults accepts both raw Helm chart values and these instance spec-level fields, which the operator pulls into the instance spec at reconcile time: version, image, database, redis, s3, admin, mail, ingress, oidc, apps, backups, maintenance, persistence, cronjob, livenessProbe, readinessProbe, startupProbe, resources, replicas, php, extraVolumes, extraVolumeMounts, placement. Instance values win on conflict. See the Profiles guide for a worked example.

API Endpoints

Nextcloud Endpoints

GET    /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextclouds
GET    /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextclouds/{name}
POST   /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextclouds
PUT    /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextclouds/{name}
DELETE /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextclouds/{name}

NextcloudInstance Endpoints

GET    /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextcloudinstances
GET    /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextcloudinstances/{name}
POST   /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextcloudinstances
PUT    /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextcloudinstances/{name}
DELETE /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextcloudinstances/{name}

NextcloudProfile Endpoints (Cluster-Scoped)

GET    /apis/k8s.bnerd.com/v1alpha1/nextcloudprofiles
GET    /apis/k8s.bnerd.com/v1alpha1/nextcloudprofiles/{name}
POST   /apis/k8s.bnerd.com/v1alpha1/nextcloudprofiles
PUT    /apis/k8s.bnerd.com/v1alpha1/nextcloudprofiles/{name}
DELETE /apis/k8s.bnerd.com/v1alpha1/nextcloudprofiles/{name}

Nextcloud safe-fallback contract: the operator validates every reference on the Nextcloud CR (spec.profile, spec.poolSelector) before doing any work. If a reference can't be honoured (typo'd profile, empty pool), it blocks with an InstanceAssigned=False condition + Warning event and retries every 60 s — never silently spawning a misconfigured instance. See Pool design — Modes, validation, and the safe-fallback contract.

NextcloudPool Endpoints (Cluster-Scoped)

GET    /apis/k8s.bnerd.com/v1alpha1/nextcloudpools
GET    /apis/k8s.bnerd.com/v1alpha1/nextcloudpools/{name}
POST   /apis/k8s.bnerd.com/v1alpha1/nextcloudpools
PUT    /apis/k8s.bnerd.com/v1alpha1/nextcloudpools/{name}
DELETE /apis/k8s.bnerd.com/v1alpha1/nextcloudpools/{name}

Notable lifecycle/status fields:

Field Type Description
spec.lifecycle.recreateOnProfileChange boolean (default false) When true, deletes unassigned pool instances when the referenced profile changes — either profileRef.name swap or content edit (detected via SHA256 digest by the reconcile timer). Assigned instances are sticky and never recreated. See Pool design — Profile changes and instance recreation.
status.observedProfile.{name,digest,observedAt} object Last observed profile snapshot used for content-change detection. Always recorded for observability.

SignalingServer Endpoints (Cluster-Scoped)

GET    /apis/k8s.bnerd.com/v1alpha1/signalingservers
GET    /apis/k8s.bnerd.com/v1alpha1/signalingservers/{name}
POST   /apis/k8s.bnerd.com/v1alpha1/signalingservers
PUT    /apis/k8s.bnerd.com/v1alpha1/signalingservers/{name}
DELETE /apis/k8s.bnerd.com/v1alpha1/signalingservers/{name}

RecordingServer Endpoints (Cluster-Scoped)

GET    /apis/k8s.bnerd.com/v1alpha1/recordingservers
GET    /apis/k8s.bnerd.com/v1alpha1/recordingservers/{name}
POST   /apis/k8s.bnerd.com/v1alpha1/recordingservers
PUT    /apis/k8s.bnerd.com/v1alpha1/recordingservers/{name}
DELETE /apis/k8s.bnerd.com/v1alpha1/recordingservers/{name}

NextcloudCommand Endpoints

GET    /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextcloudcommands
GET    /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextcloudcommands/{name}
POST   /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextcloudcommands
DELETE /apis/k8s.bnerd.com/v1alpha1/namespaces/{namespace}/nextcloudcommands/{name}

NextcloudCommand.spec is immutable — PUT/PATCH to spec is rejected by the operator. Re-run by creating a new resource.

spec.lifecycle is OnDemand (default) or OnReady. OnReady waits for the target instance to be Ready (and to have a Running+Ready pod) before running. spec.beforeScript is an optional bash setup script executed via /bin/bash -c before commands; non-zero exit fails the run and skips commands.

Operator-managed lifecycle hooks are declared on NextcloudInstance.spec.hooks (or upstream Nextcloud / Profile / Pool) and materialized as NCCs at three triggers:

  • onFirstReady — once per instance, on the first-ever Ready.
  • onAssignmentReady — once per assignment event (pool instance bound to a Nextcloud).
  • onEveryReady — every Ready edge (fresh NCC per edge; bounded by NCC TTL).

A hook NCC ending in Failed surfaces as a LifecycleHookFailed=True condition on the NCI; the NCI's own phase stays Ready. See the Commands guide for details.

Using the API

With kubectl

# Create a Nextcloud instance
kubectl apply -f nextcloudinstance.yaml

# List instances
kubectl get nci -n nextcloud

# Get instance details
kubectl describe nci my-nextcloud -n nextcloud

# Delete instance
kubectl delete nci my-nextcloud -n nextcloud

With Python (Kubernetes Client)

from kubernetes import client, config

config.load_kube_config()
api = client.CustomObjectsApi()

# List Nextcloud instances
nextclouds = api.list_namespaced_custom_object(
    group="k8s.bnerd.com",
    version="v1alpha1",
    namespace="default",
    plural="nextclouds"
)

# Create instance
body = {
    "apiVersion": "k8s.bnerd.com/v1alpha1",
    "kind": "Nextcloud",
    "metadata": {"name": "my-nextcloud"},
    "spec": {
        "profile": "production",
        "poolSelector": {"matchLabels": {"pool": "default"}}
    }
}

api.create_namespaced_custom_object(
    group="k8s.bnerd.com",
    version="v1alpha1",
    namespace="default",
    plural="nextclouds",
    body=body
)

Field Reference

NextcloudInstance Spec Fields

Field Type Default Description
profile string - Profile to use (production, testing, development, or custom)
version string 29 Nextcloud version (Docker tag)
image object - Custom container image (overrides version map and profile defaults)
image.repository string - Container image repository
image.tag string - Container image tag
image.pullPolicy string - Pull policy (Always, IfNotPresent, Never)
image.pullSecrets array - Image pull secrets for private registries
replicas integer 1 Number of pod replicas
ingress object - Ingress configuration
database object - Database configuration
redis object - Redis configuration
s3 object - S3 object storage configuration
admin object - Admin credentials
mail object - Mail/SMTP configuration
oidc object - OIDC/SSO configuration
resources object - Resource requests/limits
persistence object - Persistent storage configuration
cronjob object - Cron job configuration
livenessProbe object - Liveness probe overrides
readinessProbe object - Readiness probe overrides
startupProbe object - Startup probe overrides
license_key string - Nextcloud Enterprise license key
apps object - Declarative Nextcloud app management
backups object - Automated data backup configuration
php object - PHP / FPM / Apache MPM / preview tuning. Sane defaults shipped in every built-in profile prevent image-upload from blocking the instance. See the PHP & Preview Tuning guide.
extraVolumes array - Extra volumes appended to the Nextcloud pod (chart nextcloud.extraVolumes).
extraVolumeMounts array - Extra volume mounts on the Nextcloud container (chart nextcloud.extraVolumeMounts).
helm object - Helm chart/values overrides
placement object - Pod scheduling constraints for the Nextcloud app and cron pod (nodeSelector, tolerations, affinity, topologySpreadConstraints). See Workload Placement.

Ingress Configuration

Field Type Default Description
enabled boolean true Enable ingress. Set to false to disable external access.
host string - Hostname for the ingress (e.g., nextcloud.example.com). Required if enabled=true.
className string nginx IngressClass to use (e.g., nginx, traefik)
annotations object - Additional annotations for the ingress
tls.enabled boolean true Enable TLS/HTTPS
tls.secretName string - Name of TLS secret (defaults to <instance-name>-tls)
trustedProxies array of strings ["10.0.0.0/8"] IP/CIDR ranges of trusted reverse proxies. Auto-sets trusted_proxies in Nextcloud PHP config.
forwardedForHeaders array of strings ["HTTP_X_FORWARDED_FOR"] HTTP headers carrying the real client IP. Auto-sets forwarded_for_headers in Nextcloud PHP config.

When ingress is enabled, the operator automatically configures overwriteprotocol, overwritehost, trusted_proxies, and forwarded_for_headers in Nextcloud's PHP config. This can be overridden by providing a custom bnerd.config.php via spec.helm.values.nextcloud.configs.

Database Configuration

Field Type Default Description
type string postgresql Database type (postgresql or mysql)
managed boolean false Create managed PostgreSQL cluster via Percona PG Operator
deleteOnCleanup boolean false Delete the managed PerconaPGCluster when the instance is deleted. Ignored for unmanaged DBs. Note: when the instance owns its namespace, namespace deletion removes the DB regardless — see Deletion & Cleanup
credentialsSecret string - Secret name with credentials (overrides inline values)
host string - Database host (ignored if credentialsSecret set)
port integer 5432 Database port
name string nextcloud Database name
user string nextcloud Database user
password string - Database password
postgres object - PostgreSQL cluster config (only when managed: true)

Data Backup Configuration (spec.backups.data)

Field Type Default Description
enabled boolean false Enable automated S3 data backup
bucket string - S3 bucket name for backup storage
endpoint string - S3-compatible endpoint URL
region string - S3 region
credentialsSecret string - Secret with backup credentials (keys: accessKey, secretKey)
schedule string "0 3 * * *" Cron schedule for backup jobs
deleteOnCleanup boolean false Delete backup data when instance is deleted

Secret References

All credential sections support credentialsSecret. See Secret Management for details.

Section Secret Keys
database.credentialsSecret host, port, name, user, password
redis.credentialsSecret host, port, password
s3.credentialsSecret bucket, endpoint, region, accessKey, secretKey
admin.credentialsSecret username, password, email
mail.credentialsSecret fromAddress, domain, smtpHost, smtpPort, smtpSecure, smtpAuthType, smtpName, smtpPassword

App Management (spec.apps)

Declarative Nextcloud app management. See below for supported apps.

Well-Known Apps

App key Configuration Description
richdocuments enabled, wopiUrl, wopiAllowlist Nextcloud Office / Collabora
spreed enabled, stunServers, turnServers, signalingServers, recording Nextcloud Talk
calendar enabled Nextcloud Calendar
contacts enabled Nextcloud Contacts
deck enabled Nextcloud Deck (Kanban)
tasks enabled Nextcloud Tasks
notes enabled Nextcloud Notes
mail enabled Nextcloud Mail client
collectives enabled Nextcloud Collectives (team wikis)
whiteboard enabled Nextcloud Whiteboard
forms enabled Nextcloud Forms
admin_audit enabled Admin Audit Log
groupfolders enabled Group Folders
photos enabled Nextcloud Photos
previewgenerator enabled Preview Generator

Custom Apps

apps:
  custom:
    - appId: files_retention
      enabled: true
    - appId: announcementcenter
      enabled: false

Note

Setting enabled: false disables an app. Removing an app entry entirely does not uninstall it — this prevents accidental data loss.

Status

Version Resolution

status:
  versionResolution:
    requestedVersion: "32.0.6"
    resolvedVersion: "32.0.6"
    chartVersion: "8.9.1"
    resolvedBy: builtin

Supported Versions

The following Nextcloud versions are shipped in the default NextcloudVersionMap CRD. Use spec.version with any of these values, or set spec.helm.version to override. To add custom versions or override image defaults, edit the NextcloudVersionMap/default resource.

Nextcloud Version Helm Chart Version
33.0.3 9.0.6
33.0.2 9.0.5
33.0.0 9.0.4
32.0.9 8.9.1
32.0.8 8.9.1
32.0.6 8.9.1
32.0.5 8.9.0
32.0.3 8.8.1
32.0.2 8.6.0
32.0.1 8.5.2
32.0.0 8.5.0
31.0.9 8.0.3
31.0.8 8.0.1
31.0.7 7.0.1
30.0.10 6.6.10
30.0.6 6.6.9
30.0.5 6.6.3
30.0.4 6.6.2
30.0.3 6.3.1
30.0.2 6.3.0
30.0.1 6.2.1
30.0.0 6.1.0
29.0.6 5.5.6
29.0.5 5.5.3
29.0.4 5.5.2
29.0.3 5.2.2
29.0.2 5.0.1
29.0.1 5.0.0
29.0.0 4.6.9
28.0.4 4.6.6
28.0.3 4.6.4
28.0.2 4.6.3
28.0.1 4.5.12
28.0.0 4.5.9

Aliases: latest and stable both resolve to 33.0.3.

Prefix resolution: Setting spec.version: "33" resolves to the latest known 33.x.y patch (currently 33.0.3).

Phase Values

  • Pending: kopf has not picked up the CR yet
  • Creating: Operator is provisioning DB / secrets / S3 / HelmRelease, including waiting on managed dependencies (PerconaPGCluster spin-up). Normal database initialization stays in this phase — inspect status.database for the cause.
  • Deploying: HelmRelease applied; waiting for Flux to roll out the chart and for the workload (Deployment, Endpoints, Ingress) to become ready
  • Ready: HelmRelease Ready=True and Deployment has all ready replicas and Service has ready endpoints and (if an Ingress exists) the Ingress has a load-balancer address
  • Updating: Reserved for future use
  • Failed: An error blocks progress. The operator keeps retrying transient failures (database provisioning timeout, HelmRelease reconcile error) — Failed is informational so monitoring can alert. Configuration errors propagate as kopf PermanentError and require manual fix.

phase: Ready is set exclusively by the 30-second status timer after the layered readiness gate passes. on_create, on_update, and force_reconcile all leave the instance in Deploying. Inspect status.workload for per-component check results and status.conditions[type=Ready] for the machine-readable reason (WaitingForHelmRelease, WaitingForPods, WaitingForEndpoints, WaitingForIngress, or AllResourcesReady).

status.database is always populated and mirrors the DatabaseReady condition with drill-down fields (managed, type, clusterName, ready, reason, message, observedAt).

RBAC

To interact with these resources, you need appropriate RBAC permissions:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: nextcloud-manager
rules:
  - apiGroups: ["k8s.bnerd.com"]
    resources: ["nextclouds", "nextcloudinstances", "nextcloudpools",
                "nextcloudprofiles", "signalingservers", "recordingservers"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]