Skip to content

About

A helm chart to deploy https://opencloud.eu

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

OpenCloud

OpenCloud Helm chart

Run OpenCloud file sharing and collaboration on Kubernetes,
with collaborative editing, optional CalDAV/CardDAV and full-text search.

Chart version OpenCloud version CI Release

OCI registry Release signing Images pinned by digest Renovate configuration License


The chart deploys OpenCloud as a single-process StatefulSet with persistent configuration and data. The yjs server is enabled by default. Radicale and Apache Tika are optional companions; identity providers, office servers and other external services are configured through values.

Note

CI checks chart rendering, values validation, manifest schemas, policies and generated documentation. It does not run the containers. A separate kind-based end-to-end suite is available; validate the integrations against your own infrastructure before production use.

Contents

Features

Storage Local files or S3-compatible object storage, with persistent local metadata
Identity Built-in identity services or external OIDC, with optional external LDAP and configurable role mapping
Collaboration yjs editing, external WOPI office integration, optional Radicale and Apache Tika
Exposure Ingress or Gateway API HTTPRoute; configurable proxy routes and Content Security Policy
Security Non-root containers, read-only root filesystems, dropped capabilities, no ServiceAccount token and images pinned by digest
Observability Health probes, Prometheus metrics, optional bearer token and ServiceMonitor
GitOps No Helm hooks; existing Secrets for credentials and optional externally managed service secrets
Release tooling OCI publishing to GHCR, cosign signing and Renovate configuration

Requirements

  • A Kubernetes cluster and Helm; CI uses Helm 4.
  • Persistent storage for configuration and data, or existing claims.
  • A public hostname with DNS, HTTPS termination and a certificate trusted by browsers and OpenCloud. The hostname must also resolve and be reachable from inside the cluster.
  • External services for the integrations you enable: OIDC/LDAP, S3, SMTP, an office server or an antivirus scanner.
  • Optional: Gateway API CRDs for HTTPRoute, Prometheus Operator CRDs for ServiceMonitor, and a NetworkPolicy-capable CNI for Radicale's access restriction.

Install

From a checkout, create the namespace, initial administrator Secret and TLS Secret:

kubectl create namespace opencloud
kubectl --namespace opencloud create secret generic opencloud-admin \
  --from-literal=adminPassword="$(openssl rand -base64 24)"
kubectl --namespace opencloud create secret tls opencloud-tls \
  --cert=/path/to/fullchain.pem --key=/path/to/privkey.pem

The certificate must cover your public hostname. Save these settings as my-values.yaml, replacing the hostname and ingress class for your cluster:

host: cloud.example.org
admin:
  existingSecret: opencloud-admin
ingress:
  enabled: true
  className: nginx
  tls:
    - secretName: opencloud-tls
      hosts: [cloud.example.org]
helm install opencloud . --namespace opencloud -f my-values.yaml

Bitnami Common is vendored in charts/, so a checkout needs no dependency download. To install a published version, replace . with oci://ghcr.io/comexos/charts/opencloud and add --version 0.1.0.

The chart validates required settings and credential references during rendering. It cannot verify that Secrets exist, storage can be provisioned or external services are reachable. For an example with Keycloak, S3, SMTP and Collabora, see examples/keycloak-s3.yaml.

Verify the signature

The release workflow signs published chart digests with cosign:

cosign verify ghcr.io/comexos/charts/opencloud:0.1.0 \
  --certificate-identity-regexp '^https://github\.com/comexos/opencloud-chart/\.github/workflows/release\.yml@refs/tags/v' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

First-time setup

Open https://cloud.example.org and sign in as admin with the password stored in opencloud-admin. Retrieve it with:

kubectl --namespace opencloud get secret opencloud-admin \
  -o jsonpath='{.data.adminPassword}' | base64 --decode

On first start, an init container runs opencloud init and writes service secrets, IDs and the initial administrator password to /etc/opencloud/opencloud.yaml on the config volume. Later starts reuse that file. The administrator Secret supplies the initial password; later password changes belong in OpenCloud's account management.

Preserve the config volume together with the data volume. Its generated secrets and identifiers are needed to access stored data. To supply those values yourself from the outset, use service secrets.

Configuration

Every option is listed under Values. The sections below explain how the settings fit together.

Images

All four container images are pinned by digest in values.yaml. Changing a tag alone does not change the image: set the corresponding digest too, or clear it to use the tag. This applies to image, yjs.image, radicale.image and tika.image. global.imageRegistry replaces their registries; a mirror must contain every enabled image.

The main image uses opencloudeu/opencloud-rolling. Renovate is configured to update image tags and digests together, along with appVersion for OpenCloud. Keep image fields in the order registry, repository, tag, digest so its matching rules continue to work.

Credentials

Prefer existing Secrets. Plain credential values are stored in Helm release history even when rendered into the chart-managed <fullname>-env Secret.

Credential Existing Secret settings
Initial administrator admin.existingSecret, .passwordSecretKey
Internal service secrets and IDs serviceSecrets.existingSecret (fixed keys; see below)
LDAP bind identity.ldap.existingSecret, .bindPasswordSecretKey
S3 storage.s3.existingSecret, .accessKeySecretKey, .secretKeySecretKey
SMTP smtp.existingSecret, .passwordSecretKey
Metrics token metrics.token.existingSecret, .secretKey
Image pulls global.imagePullSecrets or each image's pullSecrets

Top-level existingSecret adds all keys of a Secret as environment variables. extraEnv and extraEnvVars set any other OpenCloud environment variable; an entry with the same name as a chart-set variable replaces it. When both specify the same name, extraEnvVars takes precedence over extraEnv. Names within extraEnvVars must be unique; duplicate names fail rendering. The order of extraEnvVars is preserved for Kubernetes variable references such as $(NAME).

Identity

identity.mode: builtin runs OpenCloud's own LDAP (idm) and OpenID Connect provider (idp). It needs an https:// public URL, since the built-in idp refuses other issuers.

identity.mode: oidc disables the built-in idp and trusts identity.oidc.issuer. Register a public client for the web UI (identity.oidc.webClientId, default web) and the upstream client IDs OpenCloudDesktop, OpenCloudAndroid and OpenCloudIOS for the apps. Roles come from the roles claim (see Keycloak claims). Set identity.oidc.audiences to enable access-token audience validation. Common identity configurations are:

Setup Chart values
External IdP with autoprovisioning identity.oidc.autoprovision: true (default). Users live in the built-in idm, or in an external LDAP with identity.ldap.writeEnabled: true.
Keycloak with a shared user directory identity.oidc.autoprovision: false, userClaim: uuid, userCs3Claim: userid, and identity.ldap with userSchemaId/groupSchemaId: entryUUID, disableUserMechanism: none, writeEnabled: false, serverUuid: true. See ci/full.yaml.

Setting identity.ldap.uri replaces the built-in idm with that directory. The chart does not deploy Keycloak or LDAP and does not create IdP clients, users or roles.

Keycloak claims

Federating LDAP in Keycloak does not by itself put the claims OpenCloud needs into the tokens. In the shared-directory setup, configure Keycloak so that the access token and the userinfo response of every OpenCloud client carry:

  • uuid: the value OpenCloud uses as the user ID, which is the LDAP attribute named in identity.ldap.userSchemaId (entryUUID above). In Keycloak, add a user-attribute LDAP mapper from entryUUID to a user attribute uuid (always read from LDAP), and a User Attribute protocol mapper from uuid to the claim uuid in a client scope assigned to the clients. Keycloak's own user ID is not the LDAP entryUUID unless the federation's UUID attribute makes it so; do not rely on sub.
  • roles: a multivalued claim containing the role names. OpenCloud's default mapping turns opencloudAdmin, opencloudSpaceAdmin, opencloudUser and opencloudGuest into its admin, space admin, user and user-light roles. Grant them as realm roles, directly, through groups, or with a role LDAP mapper from LDAP groups, and map them with a User Realm Role protocol mapper to the claim roles. For other names set identity.oidc.roleAssignment.mapping; OpenCloud reads that mapping only from its config file, so the chart renders it into proxy.yaml.

tests/e2e/realm.json is a minimal working realm with these mappers, used by the end-to-end test.

Service secrets

By default opencloud init generates OpenCloud's internal secrets and IDs into /etc/opencloud/opencloud.yaml on the config volume. For GitOps, provide them instead with serviceSecrets.existingSecret: the init container is skipped, nothing is generated, and every value is read from the Secret. This mode is supported with identity.mode: oidc and an external identity.ldap.uri only; the built-in idm and idp need further generated credentials and signing keys, and the chart rejects those combinations.

Create the Secret once per installation and store it like any other secret (SOPS, Sealed Secrets, an external secret store). Keep these values stable for the lifetime of the installation:

scripts/service-secrets.py generate --name opencloud-service-secrets > opencloud-service-secrets.yaml

The script uses the operating system's cryptographically secure random generator, writes random version-4 UUIDs for the IDs, and only prints; Helm never generates or rotates these values. Helm also cannot check the Secret's contents when rendering: a missing key fails at pod start, a wrong value at runtime.

Key Environment variable Purpose
storageUsersMountId STORAGE_USERS_MOUNT_ID, GATEWAY_STORAGE_USERS_MOUNT_ID ID of the user storage; part of the resource ID of every space and file
systemUserId OC_SYSTEM_USER_ID ID of the internal system user that stores system metadata such as shares and settings
graphApplicationId GRAPH_APPLICATION_ID Application ID that OpenCloud's app roles belong to
serviceAccountId OC_SERVICE_ACCOUNT_ID (also the settings service's service-account list) Account the services use to act on their own behalf
serviceAccountSecret OC_SERVICE_ACCOUNT_SECRET Credential of that account
jwtSecret OC_JWT_SECRET Signs and verifies internal access tokens
machineAuthApiKey OC_MACHINE_AUTH_API_KEY Authenticates internal service-to-service requests
systemUserApiKey OC_SYSTEM_USER_API_KEY Credential of the system user
transferSecret OC_TRANSFER_SECRET Signs upload and download transfer tokens
urlSigningSecret OC_URL_SIGNING_SECRET Signs URLs, for example image downloads by the office suite
wopiSecret COLLABORATION_WOPI_SECRET Signs and encrypts WOPI tokens for the office integration
thumbnailsTransferToken THUMBNAILS_TRANSFER_TOKEN Signs thumbnail download tokens

With service secrets supplied externally, the config volume is not needed for generated credentials; persistence.config.enabled: false replaces its volume with an emptyDir. The chart's own files (csp.yaml, proxy.yaml, apps.yaml and the others) are still mounted into it read-only.

Storage

storage.driver selects where file content lives. Choose it before the first start: switching drivers does not migrate data.

Driver File content Notes
posix (default) Data volume Upstream default
decomposed Data volume Alternative local storage layout
decomposeds3 S3 bucket Metadata stays on the data volume; set storage.s3

Whatever the driver, /var/lib/opencloud holds local service state, including NATS JetStream, the search index, thumbnails, metadata and the built-in idm database when used, so disabling persistence loses local state on pod replacement, even if file content remains in S3. The chart supports exactly one OpenCloud replica and does not provide a distributed deployment. Volumes are ReadWriteOnce by default; existingClaim adopts existing claims instead of the StatefulSet templates.

Networking

The <fullname> Service serves HTTP on service.port (default 9200); terminate TLS at the Ingress or Gateway. Set a body-size limit suitable for uploads on the controller, for example nginx.ingress.kubernetes.io/proxy-body-size: "0". gatewayAPI.httpRoute attaches to an existing Gateway instead.

OpenCloud calls its own public URL: uploads, for example, go through https://<host>/data. The host must resolve inside the cluster to the Ingress or Gateway, with a certificate the pod trusts. Use hostAliases for split-horizon setups. insecure: true skips certificate verification and is meant only for self-signed test installs.

The proxy also serves WOPI under /wopi and /collaboration, yjs under /yjs, and CalDAV/CardDAV under /caldav/, /carddav/ and their .well-known paths; no other hostnames are needed for these. proxy.additionalRoutes adds custom routes.

Web office

collaboration.enabled runs OpenCloud's collaboration (WOPI) service in the main process and points it at collaboration.app.url. Deploy the office server separately, for example with the Collabora Online chart, and allow OpenCloud as WOPI host there (aliasgroup1=https://<host>). The chart adds the office origin to the Content Security Policy.

For Euro-Office or OnlyOffice set collaboration.app.name, product: OnlyOffice and proofDisable: true, and supply an app registry that makes it the default for OOXML types through collaboration.appRegistry. Run only one office app: there is no locking between apps.

Sharing

Public links require passwords by default (sharing.publicShareMustHavePassword: true). sharing.publicWriteableShareMustHavePassword can require passwords specifically on writable links when the general requirement is disabled. passwordPolicy controls public-link password strength and an optional banned-password list; it does not configure LDAP or OIDC account passwords.

These settings govern passwords, not whether public links may be created. The chart currently exposes no switch to disable public-link creation or enforce share expiry.

Optional services

Values Effect
smtp.enabled Email notifications. smtp.sender is required; the notifications service exits without it.
tika.enabled or tika.externalUrl Full-text search through a bundled or external Apache Tika server.
radicale.enabled Personal calendar and address book per user, authenticated by the OpenCloud proxy. Data on its own volume.
yjs.enabled (default true) Real-time collaborative editing in the web UI through the bundled yjs server.
antivirus.enabled Scans uploads through an external ClamAV (clamavSocket: tcp://host:3310) or ICAP server. Keep the scanner's stream limit at least antivirus.maxScanSize.
web.appsConfig Configuration of web extensions, rendered into apps.yaml. Install extensions into /var/lib/opencloud/web/assets/apps with extraInitContainers.
csp.extraDirectives Additional Content Security Policy sources, for example for web extensions that embed other sites.

Monitoring

Health probes use /healthz and /readyz on the proxy's debug port 9205, which is always bound. The web port answers every path with the web UI, so it cannot serve as a health check. Readiness reflects the proxy only; backend services may still be starting for a few seconds after the pod turns ready.

metrics.enabled adds a <fullname>-metrics Service for /metrics on the same port, and metrics.serviceMonitor.enabled a ServiceMonitor (requires the Prometheus Operator CRDs). In single-process mode this endpoint covers all services. Set metrics.token to require a bearer token for /metrics; health endpoints stay open.

The ServiceMonitor and its authentication Secrets always live in the Helm release namespace. Configure Prometheus's serviceMonitorNamespaceSelector to discover that namespace and its serviceMonitorSelector to match the monitor's labels; Prometheus itself can stay in a separate monitoring namespace.

Security

All containers run as non-root with a read-only root filesystem, RuntimeDefault seccomp, no privilege escalation and all capabilities dropped. ServiceAccount token automounting is disabled; the chart grants no Kubernetes RBAC permissions. When Radicale is enabled, the chart installs an ingress NetworkPolicy allowing TCP port 5232 only from this release's OpenCloud server pods in the same namespace, because Radicale trusts their X-Remote-User header. This requires a network plugin that enforces NetworkPolicy; other policies must not grant broader access to Radicale, since allow rules are additive. Port 9205 also serves metrics and is reachable on the pod IP: restrict it and the other companions with your own NetworkPolicies.

Operations

  • Backups: back up config and data volumes together, plus the S3 bucket when using decomposeds3 and the Radicale volume when enabled. Stop services or use a consistent snapshot, and test restoration.
  • Secrets: restart the affected pods after changing an externally managed Secret used as environment variables. Keep internal service secrets and IDs stable.
  • Persistence: check PVC retention before uninstalling. Resource and claim names depend on the release name and fullnameOverride.
  • Resources: OpenCloud requests 250m CPU and 512Mi memory by default. Tune resources from measured load; the startup probe allows five minutes.
  • GitOps: the chart has no hooks. Install any required Gateway API or ServiceMonitor CRDs before applying its rendered resources.

Before production

Test browser sign-in, user and role mapping, uploads and downloads, TLS, and backup restoration against your infrastructure. If enabled, also test office editing, antivirus handling, email delivery, calendar/address-book access and full-text search results. Rendering checks cannot establish runtime correctness.

Development

Run local checks with Helm, Python and Docker:

pip install --require-hashes -r ci/requirements.txt
scripts/render-matrix.sh
scripts/validate-manifests.sh
python3 tests/render.py
python3 tests/e2e/test_harness.py
yamllint -c .yamllint.yaml .
scripts/generate-docs.sh --check

CI also checks workflow syntax and the values schema. Optional local hooks are configured in .pre-commit-config.yaml.

tests/e2e/run.sh runs a separate suite on a throwaway kind cluster with Keycloak and OpenLDAP. It exercises token-based sign-in, roles, LDAP groups, file transfers, companions, persistent state and externally managed service secrets. It requires kind, kubectl, Helm, Docker and Python and is not run by CI. The harness unit tests above do not start a cluster.

policies/kyverno/ contains optional ValidatingPolicy resources for pod hardening, image digests and resource requests. The chart does not install them. They use Deny actions without a namespace restriction; scope them or select audit actions before applying them to a shared cluster.

This README is generated from README.md.gotmpl and the # -- comments in values.yaml by helm-docs. Edit those sources and run scripts/generate-docs.sh. CI checks that the generated README is current.

Release

Bitnami Common is vendored in charts/. Keep Chart.yaml, Chart.lock and the dependency archive in sync; helm dependency build . restores the locked dependency.

Push a vX.Y.Z tag matching version in Chart.yaml to run CI, package the chart, publish it to oci://ghcr.io/comexos/charts/opencloud and sign its digest with cosign. Forks publish under their repository owner's GHCR namespace.

Values

All configuration values and their defaults
Key Type Default Description
additionalAnnotations object {} Annotations added to every resource.
additionalLabels object {} Labels added to every resource.
additionalServices list [] Extra services started inside the single OpenCloud process (OC_ADD_RUN_SERVICES). The chart adds notifications, collaboration and antivirus itself when those features are enabled.
admin.existingSecret string "" Existing Secret holding the initial administrator password.
admin.password string "" Fallback only, stored in a chart-managed Secret and visible in Helm's release history. Prefer existingSecret.
admin.passwordSecretKey string "adminPassword"
affinity object {}
antivirus.clamavSocket string "" clamd address, e.g. tcp://clamav.antivirus.svc.cluster.local:3310.
antivirus.enabled bool false
antivirus.icapUrl string "" ICAP URL, e.g. icap://icap.antivirus.svc.cluster.local:1344.
antivirus.infectedFileHandling string "abort" abort, continue or delete.
antivirus.maxScanSize string "100MB"
antivirus.maxScanSizeMode string "partial" partial scans only the first maxScanSize bytes; skip does not scan larger files. (OpenCloud's own description says "truncate", but the code only accepts partial and skip.)
antivirus.scanner string "clamav" clamav or icap
antivirus.workers int 1
archiverMaxSize string "10000000000" Maximum size in bytes of a folder download archive (FRONTEND_ARCHIVER_MAX_SIZE).
basicAuth bool false Allows HTTP Basic authentication (PROXY_ENABLE_BASIC_AUTH), for WebDAV clients without OpenID Connect support. Not recommended.
checkForUpdates bool true Lets clients check for updates (FRONTEND_CHECK_FOR_UPDATES).
collaboration.app.icon string "" Icon URL; defaults to /favicon.ico.
collaboration.app.insecure bool false Skips TLS verification of the office server.
collaboration.app.name string "CollaboraOnline" Display name and app registry name (COLLABORATION_APP_NAME), e.g. CollaboraOnline or Euro-Office.
collaboration.app.product string "Collabora" Collabora, OnlyOffice (also for Euro-Office) or Microsoft (COLLABORATION_APP_PRODUCT).
collaboration.app.proofDisable bool false Disables WOPI proof key validation, as needed for Euro-Office.
collaboration.app.url string "" Public URL of the office server (COLLABORATION_APP_ADDR). Required.
collaboration.appRegistry string "" Raw app-registry.yaml (mime types and default apps) mounted into /etc/opencloud; empty keeps OpenCloud's built-in registry.
collaboration.enabled bool false
collaboration.secureView bool true Makes the office app the secure-view app and offers the secure-view share role. Collabora only.
containerSecurityContext.allowPrivilegeEscalation bool false
containerSecurityContext.capabilities.drop[0] string "ALL"
containerSecurityContext.enabled bool true
containerSecurityContext.privileged bool false
containerSecurityContext.readOnlyRootFilesystem bool true
containerSecurityContext.runAsNonRoot bool true
csp.extraDirectives object {} Extra sources appended per directive, e.g. {frame-src: ["https://embed.diagrams.net/"]}.
csp.override string "" Replaces the generated csp.yaml entirely when set.
defaultLanguage string "" Default language of services and the web UI as an ISO 639-1 code (OC_DEFAULT_LANGUAGE). Empty means English.
demoUsers bool false Creates the public demo accounts (alan, mary, margaret, dennis, lynn; password "demo"). Never on production.
domain string "" Convenience base domain: when set and host is left empty, the public hostname becomes cloud..
excludeServices list [] Services excluded from the OpenCloud process (OC_EXCLUDE_RUN_SERVICES). The chart excludes idp, and idm with an external LDAP, in OIDC mode.
existingSecret string "" Existing Secret whose keys are all injected as environment variables (envFrom).
externalUrl string "" Full public URL (OC_URL) when it is not https://, for example with a non-standard port. Every browser-facing URL derives from it.
extraEnv object {} Extra environment variables as plain name/value pairs, for any OpenCloud setting not exposed above.
extraEnvVars list [] Extra environment variables as full Kubernetes env entries (for example valueFrom.secretKeyRef). Takes precedence over extraEnv; names must be unique.
extraInitContainers list [] Extra init containers, for example to copy web extensions into /var/lib/opencloud/web/assets/apps on the data volume.
extraSecretEnv object {} Extra environment variables from the chart-managed Secret.
extraVolumeMounts list []
extraVolumes list []
fullnameOverride string "" Overrides the full resource name used by the chart.
gatewayAPI.httpRoute.annotations object {}
gatewayAPI.httpRoute.enabled bool false
gatewayAPI.httpRoute.hostnames list [] Defaults to host.
gatewayAPI.httpRoute.parentRefs list [] Existing Gateway listeners to attach to.
global.defaultStorageClass string "" Default storage class when a persistence storageClass is unset.
global.imagePullSecrets list []
global.imageRegistry string ""
host string "" Public hostname of OpenCloud, used for OC_URL, Ingress, HTTPRoute and the WOPI source. Defaults to cloud..
hostAliases list [] OpenCloud calls its own public URL (uploads go through https:///data), so the host must resolve and be reachable from the pod. Use hostAliases when cluster DNS does not resolve it to the Ingress or Gateway.
identity.ldap.bindDn string ""
identity.ldap.bindPassword string "" Fallback only, stored in a chart-managed Secret. Prefer existingSecret.
identity.ldap.bindPasswordSecretKey string "bindPassword"
identity.ldap.disableUserMechanism string "attribute" How disabled users are detected: none, attribute or group.
identity.ldap.existingSecret string "" Existing Secret holding the bind password.
identity.ldap.groupBaseDn string ""
identity.ldap.groupCreateBaseDn string "" Subtree for groups created in OpenCloud (GRAPH_LDAP_GROUP_CREATE_BASE_DN). Empty uses groupBaseDn.
identity.ldap.groupFilter string ""
identity.ldap.groupSchemaId string "opencloudUUID"
identity.ldap.insecure bool false Skips LDAP certificate verification (OC_LDAP_INSECURE).
identity.ldap.refintEnabled bool false The server keeps group memberships consistent (GRAPH_LDAP_REFINT_ENABLED).
identity.ldap.serverUuid bool false The LDAP server generates the ID attribute (GRAPH_LDAP_SERVER_UUID), as with entryUUID.
identity.ldap.uri string "" e.g. ldaps://openldap.identity.svc.cluster.local:636. Disables the built-in idm when set.
identity.ldap.userBaseDn string ""
identity.ldap.userFilter string "(objectclass=inetOrgPerson)"
identity.ldap.userSchemaId string "opencloudUUID" Attribute holding the immutable user ID: opencloudUUID with the OpenCloud LDAP schema, entryUUID for a directory managed by Keycloak.
identity.ldap.writeEnabled bool true OpenCloud may create and change users and groups (OC_LDAP_SERVER_WRITE_ENABLED).
identity.mode string "builtin" builtin or oidc
identity.oidc.accountUrl string "" Account management page linked from the web UI (WEB_OPTION_ACCOUNT_EDIT_LINK_HREF).
identity.oidc.assignDefaultUserRole bool false Assigns the user role to new users (GRAPH_ASSIGN_DEFAULT_USER_ROLE); set it with roleAssignment.driver default.
identity.oidc.audiences list [] Allowed access-token audiences (PROXY_OIDC_AUDIENCES). Recommended for production; only honoured by OpenCloud 8.x and later.
identity.oidc.autoprovision bool true Creates users in OpenCloud's LDAP on their first login (PROXY_AUTOPROVISION_ACCOUNTS). Requires a writable LDAP: the built-in idm or ldap.writeEnabled.
identity.oidc.autoprovisionClaimUsername string "sub" Claim stored as the username of autoprovisioned accounts.
identity.oidc.issuer string "" Issuer URL including the realm, e.g. https://keycloak.example.org/realms/openCloud.
identity.oidc.roleAssignment.claim string "roles" Claim holding the role names (PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM).
identity.oidc.roleAssignment.driver string "oidc" oidc maps a claim to OpenCloud roles; default gives every user the user role.
identity.oidc.roleAssignment.mapping list [] Claim values mapped to OpenCloud roles, e.g. [{role_name: admin, claim_value: opencloud-admins}]. Empty keeps the upstream mapping: opencloudAdmin, opencloudSpaceAdmin, opencloudUser and opencloudGuest to admin, spaceadmin, user and user-light. OpenCloud reads this only from its config file, so the chart renders it into proxy.yaml.
identity.oidc.userClaim string "sub" Claim that identifies the user (PROXY_USER_OIDC_CLAIM).
identity.oidc.userCs3Claim string "username" User attribute the claim is matched against (PROXY_USER_CS3_CLAIM): username, userid or mail.
identity.oidc.webClientId string "web" Client ID of the web UI (WEB_OIDC_CLIENT_ID). The desktop and mobile apps use their upstream client IDs (OpenCloudDesktop, OpenCloudAndroid, OpenCloudIOS) unless overridden through extraEnv.
identity.oidc.webScopes string "openid profile email" Scopes requested by the web UI (WEB_OIDC_SCOPE).
image.digest string pinned, see values.yaml Multi-arch index digest of the tag. Takes precedence over the tag; clear it to float on the tag instead.
image.pullPolicy string "IfNotPresent"
image.pullSecrets list []
image.registry string "docker.io"
image.repository string "opencloudeu/opencloud-rolling"
image.tag string pinned, see values.yaml Image tag, kept in sync with the digest by Renovate.
ingress.annotations object {} Large uploads need a body size limit on the controller, e.g. nginx.ingress.kubernetes.io/proxy-body-size: "0".
ingress.className string ""
ingress.enabled bool false
ingress.tls list [] TLS entries; the host is taken from host.
initResources object {"requests":{"cpu":"50m","memory":"64Mi"}} Resources of the init container that runs opencloud init.
insecure bool false Maps to OC_INSECURE. Skips TLS verification for OpenCloud's own calls to its public URL, the IdP and office apps. Only for self-signed test setups.
livenessProbe.enabled bool true
livenessProbe.failureThreshold int 3
livenessProbe.initialDelaySeconds int 0
livenessProbe.periodSeconds int 10
livenessProbe.successThreshold int 1
livenessProbe.timeoutSeconds int 5
logLevel string "info" Maps to OC_LOG_LEVEL: panic, fatal, error, warn, info, debug or trace.
logPretty bool false Human-readable, colored logs instead of JSON (OC_LOG_PRETTY, OC_LOG_COLOR).
metrics.enabled bool false
metrics.serviceMonitor.additionalLabels object {}
metrics.serviceMonitor.annotations object {}
metrics.serviceMonitor.enabled bool false
metrics.serviceMonitor.honorLabels bool false
metrics.serviceMonitor.interval string "30s"
metrics.serviceMonitor.metricRelabelings list []
metrics.serviceMonitor.relabelings list []
metrics.serviceMonitor.scrapeTimeout string ""
metrics.token.existingSecret string ""
metrics.token.secretKey string "token"
metrics.token.value string "" Fallback only, stored in a chart-managed Secret. Prefer existingSecret.
nameOverride string "" Overrides the chart name used in resource names.
nodeSelector object {}
passwordPolicy.bannedPasswords list [] Passwords rejected by the policy, one per entry. Rendered into banned-password-list.txt; empty disables the list.
passwordPolicy.disabled bool false
passwordPolicy.minCharacters int 8
passwordPolicy.minDigits int 1
passwordPolicy.minLowercaseCharacters int 1
passwordPolicy.minSpecialCharacters int 1
passwordPolicy.minUppercaseCharacters int 1
persistence.config.accessMode string "ReadWriteOnce"
persistence.config.enabled bool true Persistent volume for /etc/opencloud. Required unless serviceSecrets.existingSecret provides the service secrets; then an emptyDir suffices. Choose the volume layout before installation.
persistence.config.existingClaim string "" Use an existing claim instead of the StatefulSet volume claim template.
persistence.config.size string "1Gi"
persistence.config.storageClass string ""
persistence.data.accessMode string "ReadWriteOnce"
persistence.data.existingClaim string "" Use an existing claim instead of the StatefulSet volume claim template.
persistence.data.size string "50Gi"
persistence.data.storageClass string ""
persistence.enabled bool true
podAnnotations object {}
podLabels object {}
podSecurityContext.enabled bool true
podSecurityContext.fsGroup int 1000 The published image's non-root user; adjust if a custom image uses a different UID/GID.
podSecurityContext.fsGroupChangePolicy string "OnRootMismatch"
podSecurityContext.runAsGroup int 1000
podSecurityContext.runAsNonRoot bool true
podSecurityContext.runAsUser int 1000
podSecurityContext.seccompProfile.type string "RuntimeDefault"
proxy.additionalRoutes list [] Extra routes appended to the proxy's default policy (proxy.yaml additional_policies), e.g. [{endpoint: /app/, backend: "http://app:8080", unprotected: true}].
radicale.affinity object {}
radicale.config string "" Replaces the generated Radicale configuration file entirely when set. Keep [auth] type = http_x_remote_user: the proxy passes the user in X-Remote-User.
radicale.containerSecurityContext.allowPrivilegeEscalation bool false
radicale.containerSecurityContext.capabilities.drop[0] string "ALL"
radicale.containerSecurityContext.enabled bool true
radicale.containerSecurityContext.privileged bool false
radicale.containerSecurityContext.readOnlyRootFilesystem bool true
radicale.containerSecurityContext.runAsNonRoot bool true
radicale.enabled bool false
radicale.image.digest string pinned, see values.yaml Multi-arch index digest of the tag. Takes precedence over the tag; clear it to float on the tag instead.
radicale.image.pullPolicy string "IfNotPresent"
radicale.image.pullSecrets list []
radicale.image.registry string "docker.io"
radicale.image.repository string "opencloudeu/radicale"
radicale.image.tag string pinned, see values.yaml Image tag, kept in sync with the digest by Renovate.
radicale.nodeSelector object {}
radicale.persistence.accessMode string "ReadWriteOnce"
radicale.persistence.enabled bool true
radicale.persistence.existingClaim string ""
radicale.persistence.size string "5Gi"
radicale.persistence.storageClass string ""
radicale.podAnnotations object {}
radicale.podLabels object {}
radicale.podSecurityContext.enabled bool true
radicale.podSecurityContext.fsGroup int 1000
radicale.podSecurityContext.fsGroupChangePolicy string "OnRootMismatch"
radicale.podSecurityContext.runAsGroup int 1000
radicale.podSecurityContext.runAsNonRoot bool true
radicale.podSecurityContext.runAsUser int 1000
radicale.podSecurityContext.seccompProfile.type string "RuntimeDefault"
radicale.resources.requests.cpu string "50m"
radicale.resources.requests.memory string "64Mi"
radicale.tolerations list []
readinessProbe.enabled bool true
readinessProbe.failureThreshold int 3
readinessProbe.initialDelaySeconds int 0
readinessProbe.periodSeconds int 10
readinessProbe.successThreshold int 1
readinessProbe.timeoutSeconds int 5
resources object {"requests":{"cpu":"250m","memory":"512Mi"}} OpenCloud's requests are starting points; the single process runs every service, so tune them from measured load.
service.annotations object {}
service.ipFamilies list []
service.ipFamilyPolicy string "" SingleStack, PreferDualStack or RequireDualStack. Empty keeps the cluster default.
service.port int 9200
service.type string "ClusterIP"
serviceAccount.annotations object {}
serviceAccount.automountServiceAccountToken bool false
serviceAccount.create bool true
serviceAccount.labels object {}
serviceAccount.name string ""
serviceSecrets.existingSecret string "" Existing Secret with the keys jwtSecret, machineAuthApiKey, systemUserApiKey, systemUserId, transferSecret, urlSigningSecret, graphApplicationId, serviceAccountId, serviceAccountSecret, wopiSecret, thumbnailsTransferToken and storageUsersMountId.
sharing.publicShareMustHavePassword bool true OC_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD.
sharing.publicWriteableShareMustHavePassword bool false OC_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD.
smtp.authentication string "auto" login, plain, crammd5, none or auto.
smtp.enabled bool false
smtp.encryption string "starttls" starttls, ssltls or none.
smtp.existingSecret string "" Existing Secret holding the SMTP password.
smtp.host string ""
smtp.insecure bool false Skips certificate verification of the SMTP server.
smtp.password string "" Fallback only, stored in a chart-managed Secret. Prefer existingSecret.
smtp.passwordSecretKey string "password"
smtp.port int 587
smtp.sender string "" Sender address, e.g. "OpenCloud noreply@example.org". Required: the notifications service exits without it.
smtp.username string ""
startupProbe.enabled bool true
startupProbe.failureThreshold int 60
startupProbe.initialDelaySeconds int 0
startupProbe.periodSeconds int 5
startupProbe.successThreshold int 1
startupProbe.timeoutSeconds int 5
storage.driver string "posix" posix (upstream default, files on the data volume), decomposed, or decomposeds3 (metadata on the data volume, file content in S3).
storage.s3.accessKey string "" Fallback only, stored in a chart-managed Secret. Prefer existingSecret. Both are required together when existingSecret is not set.
storage.s3.accessKeySecretKey string "accessKey"
storage.s3.bucket string ""
storage.s3.endpoint string ""
storage.s3.existingSecret string "" Existing Secret with the access and secret key.
storage.s3.region string "default"
storage.s3.secretKey string ""
storage.s3.secretKeySecretKey string "secretKey"
terminationGracePeriodSeconds int 60 Seconds OpenCloud gets to shut down and flush NATS and the search index.
tika.affinity object {}
tika.containerSecurityContext.allowPrivilegeEscalation bool false
tika.containerSecurityContext.capabilities.drop[0] string "ALL"
tika.containerSecurityContext.enabled bool true
tika.containerSecurityContext.privileged bool false
tika.containerSecurityContext.readOnlyRootFilesystem bool true
tika.containerSecurityContext.runAsNonRoot bool true
tika.enabled bool false
tika.externalUrl string "" Existing Tika server, e.g. http://tika.search.svc.cluster.local:9998. Used instead of the bundled deployment.
tika.image.digest string pinned, see values.yaml Multi-arch index digest of the tag. Takes precedence over the tag; clear it to float on the tag instead.
tika.image.pullPolicy string "IfNotPresent"
tika.image.pullSecrets list []
tika.image.registry string "docker.io"
tika.image.repository string "apache/tika"
tika.image.tag string pinned, see values.yaml Image tag, kept in sync with the digest by Renovate.
tika.nodeSelector object {}
tika.podAnnotations object {}
tika.podLabels object {}
tika.podSecurityContext.enabled bool true
tika.podSecurityContext.runAsGroup int 35002
tika.podSecurityContext.runAsNonRoot bool true
tika.podSecurityContext.runAsUser int 35002
tika.podSecurityContext.seccompProfile.type string "RuntimeDefault"
tika.resources.requests.cpu string "100m"
tika.resources.requests.memory string "512Mi"
tika.tolerations list []
tolerations list []
topologySpreadConstraints list []
web.appsConfig object {} Configuration of installed web extensions, rendered into apps.yaml.
yjs.affinity object {}
yjs.containerSecurityContext.allowPrivilegeEscalation bool false
yjs.containerSecurityContext.capabilities.drop[0] string "ALL"
yjs.containerSecurityContext.enabled bool true
yjs.containerSecurityContext.privileged bool false
yjs.containerSecurityContext.readOnlyRootFilesystem bool true
yjs.containerSecurityContext.runAsNonRoot bool true
yjs.enabled bool true
yjs.extraEnv object {}
yjs.image.digest string pinned, see values.yaml Multi-arch index digest of the tag. Takes precedence over the tag; clear it to float on the tag instead.
yjs.image.pullPolicy string "IfNotPresent"
yjs.image.pullSecrets list []
yjs.image.registry string "docker.io"
yjs.image.repository string "opencloudeu/yjs"
yjs.image.tag string pinned, see values.yaml Image tag, kept in sync with the digest by Renovate.
yjs.nodeSelector object {}
yjs.podAnnotations object {}
yjs.podLabels object {}
yjs.podSecurityContext.enabled bool true
yjs.podSecurityContext.runAsGroup int 1000
yjs.podSecurityContext.runAsNonRoot bool true
yjs.podSecurityContext.runAsUser int 1000
yjs.podSecurityContext.seccompProfile.type string "RuntimeDefault"
yjs.resources.requests.cpu string "50m"
yjs.resources.requests.memory string "128Mi"
yjs.shutdownGracePeriodMs int 15000 Milliseconds the server gets to flush documents on shutdown; keep it below terminationGracePeriodSeconds.
yjs.terminationGracePeriodSeconds int 20
yjs.tolerations list []

License

Copyright 2026 Thomas Kaltenstein (Sovereign Systems). Licensed under the Apache License, Version 2.0; bundled third-party components are listed in NOTICE. The deployed images have their own licences.

About

A helm chart to deploy https://opencloud.eu

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages