Nextcloud
A self-hosted content collaboration platform for file sync, sharing, and productivity.
Nextcloud is the most popular open-source file hosting and collaboration platform. It provides file sync and share, calendar, contacts, document editing (via Collabora Online), and hundreds of apps through its app store. Self-hosting keeps all files and productivity data on your own infrastructure, avoiding per-user cloud storage fees.
Alternatives considered
Cloud Hosted
| Tool | Open Source | Free Tier | Monthly Cost |
|---|---|---|---|
| Google Workspace | No | Limited | From $7/user |
| Dropbox | No | Limited | From $9.99/mo |
| Microsoft 365 | No | No | From $6/user |
Self Hosted
| Tool | Open Source | Full Features | Notes |
|---|---|---|---|
| Seafile | Yes | Yes | Fast file sync, lighter than Nextcloud |
Installation
Architecture
- HelmRelease: Nextcloud PHP-FPM application;
collaboraHelm chart for Collabora Online document editing - StatefulSet: Valkey (
valkey/valkey, digest-pinned via Renovate) for caching and session management - Database: CNPG PostgreSQL cluster with Longhorn-encrypted PVCs
- Networking: HTTPRoute via public gateway
Security
- Valkey: capabilities dropped (Nextcloud container securityContext commented out in chart values)
- Longhorn PVCs encrypted at rest via SOPS-managed keys
Updates
Managed by Renovate. Valkey image is digest-pinned.
Data Management
- Database: CNPG PostgreSQL cluster (Longhorn-encrypted PVCs)
- PVCs: Longhorn-encrypted PVCs for Nextcloud data (via HelmRelease)
- Backups: k8up
Schedules to Hetzner and Backblaze via restic, covering the Nextcloud data PVC and the database dump from thebackups-cnpgPreBackupPod.
User Management
OIDC present in SOPS-encrypted secret (Nextcloud Social Login app). Users can authenticate via the cluster's OIDC provider. Internal user management also available via admin panel.
Configuration Management
- PHP limits (
PHP_MEMORY_LIMIT,PHP_UPLOAD_LIMIT),OVERWRITEPROTOCOLfrom ConfigMap - OIDC and admin credentials from SOPS-encrypted secret
- Database credentials injected from CNPG-generated secret
Administration
Manual upgrade
During upgrades with Helm it may happen that some update procedures get stuck or are not automatically executed. Nextcloud will be put into 'maintenance mode'. Manual intervention is required to finish the upgrade procedure:
After exec into the container the following commands are used
php occ upgrade
After successful execution, maintenance mode can be switched off:
php occ maintenance:mode --off
From outside of the pod the following command can be used
kubectl exec -it NEXTCLOUD_POD -n nextcloud -- php occ maintenance:mode --off
Usage
Sync files from desktop or mobile clients. Share files and folders with internal users or external links. Use Collabora Online (accessible within Nextcloud) to view and edit office documents in the browser. Calendar and contacts sync with CalDAV/CardDAV clients.
Cluster-specific deviations from the above live in the per-cluster README — see k8s/apps/nextcloud/talos/README.md.
Cluster Deployment
Nextcloud — Talos cluster
Deviations from defaults
- Startup probe with a 30-minute budget. The image upgrades in place during container start: it rsyncs the new code,
version.phpincluded, then runsocc upgrade, and only then starts Apache. The chart's liveness probe begins after 10 seconds and killed the container about 40 seconds in, in the middle of the migration. Becauseversion.phpwas already the new one, the next start found nothing to upgrade and the instance stayed in maintenance mode withneedsDbUpgrade, every release. The startup probe holds liveness and readiness back untilstatus.phpanswers. before-startinghook as the safety net. The entrypoint runs it on every start, after its own version check. It finishes an upgrade that was interrupted anyway (drain, OOM, eviction), leaves maintenance mode, and appliesdb:add-missing-indices,-columnsand-primary-keys. A failingocc upgradefails the start on purpose, so the reason shows up as a crashloop with a log line.- No CPU limit, 1536Mi memory. Throttled to 500m the rsync and migration took long enough to meet the probe, and
PHP_MEMORY_LIMIT=512Mnext to Apache does not fit into 768Mi. - Helm never rolls an upgrade back (
upgrade.remediation.retries: 0, timeout 35m, above the probe budget). After a failed upgrade the volume holds new code and a half-migrated schema, and the old image refuses to start on data newer than itself; the release stays failed and is retried forward.
- HelmRelease:
collabora-online@1.3.6 - HelmRelease:
nextcloud@9.4.0 - HelmRepo:
collabora(oci://ghcr.io/collaboraonline/charts/collabora-online) - HelmRepo:
nextcloud(oci://ghcr.io/nextcloud/helm/nextcloud) - Image:
valkey/valkey:9.1.2-alpine@sha256:48332870af354a799964c0012ae1194a0bf2bf894eb508f945810596dc2d8d11
Rendered manifests (kustomize build)
apiVersion: apps/v1
kind: StatefulSet
metadata:
annotations:
kustomize.toolkit.fluxcd.io/force: enabled
name: valkey
namespace: nextcloud
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: valkey
serviceName: valkey
template:
metadata:
labels:
app.kubernetes.io/name: valkey
spec:
containers:
- args:
- valkey-server
image: valkey/valkey:9.1.2-alpine@sha256:48332870af354a799964c0012ae1194a0bf2bf894eb508f945810596dc2d8d11
livenessProbe:
initialDelaySeconds: 10
periodSeconds: 10
tcpSocket:
port: 6379
name: valkey
ports:
- containerPort: 6379
name: client
readinessProbe:
initialDelaySeconds: 3
periodSeconds: 5
tcpSocket:
port: 6379
resources:
limits:
memory: 512Mi
requests:
cpu: 50m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
volumeMounts:
- mountPath: /conf
name: conf
- mountPath: /data
name: data
priorityClassName: tier-1
securityContext:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 999
seccompProfile:
type: RuntimeDefault
volumes:
- emptyDir: {}
name: conf
- emptyDir: {}
name: data