# ServiceDefinition: nextcloud # Source of truth: spec docs/13-service-catalog.md row 7; docs/15-identity-and-access.md; docs/04. # public file-sync | egress internet | data on Longhorn (irreplaceable, DR-critical) | auth oidc. # # DR-critical (docs/13 "DR-critical data"): the user data lives on the 3-replica `longhorn` tier and # is backed up off-cluster (backup.policy daily-offcluster; R-STATE-03). Nextcloud is stateless code # over (a) its /var/www/html Longhorn PVC and (b) an external PostgreSQL — the first CNPG-DB app, # establishing the reusable pattern (its DB is a CloudNativePG Cluster, apps/nextcloud-db.yaml). # # DB WIRING (schema >=1.2.0 env/envFrom): the app reaches its PostgreSQL cross-namespace at # nextcloud-db-rw.nextcloud-db:5432 (the CNPG read-write Service). Its owner credentials are the # SAME password held in two SOPS secrets — nextcloud-db-app (basic-auth, ns nextcloud-db; consumed by # the CNPG Cluster's initdb) and nextcloud-bootstrap (ns nextcloud; consumed here as db-password). # A Pod can only read Secrets in its OWN namespace, so the shared password is duplicated across the # two encrypted files rather than replicated cross-namespace (documented in apps/nextcloud-db.yaml). # Validates against schemas/servicedefinition.schema.json. name: nextcloud kind: container source: image: nextcloud:31-apache # apache variant serves on :80 (docs/13 row 7); pinned recent stable # major (R-UPD-01); update.range governs advancement within the line env: # --- PostgreSQL connection (the CNPG-DB pattern). HOST/DB/USER are literals; PASSWORD is sourced # from the in-namespace SOPS secret (the CNPG -app secret lives in ns nextcloud-db, unreachable # by a Pod secretKeyRef, so the same value is mirrored into nextcloud-bootstrap here). --- - name: POSTGRES_HOST value: nextcloud-db-rw.nextcloud-db.svc.cluster.local - name: POSTGRES_DB value: nextcloud - name: POSTGRES_USER value: nextcloud - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: nextcloud-bootstrap key: db-password # --- Break-glass local admin (docs/15 availability caveat): created on first-boot install so the # operator is never locked out by an IdP outage. Sourced from the SOPS nextcloud-bootstrap secret. --- - name: NEXTCLOUD_ADMIN_USER valueFrom: secretKeyRef: name: nextcloud-bootstrap key: admin-username - name: NEXTCLOUD_ADMIN_PASSWORD valueFrom: secretKeyRef: name: nextcloud-bootstrap key: admin-password # --- Public exposure behind the TLS-terminating shared Gateway (docs/08/09). TRUSTED_DOMAINS lets # the vhost answer for the public FQDN; OVERWRITE* make Nextcloud emit https:// self-URLs even # though it speaks plain HTTP behind the proxy. --- - name: NEXTCLOUD_TRUSTED_DOMAINS value: nextcloud.home.keithjackson.dev - name: OVERWRITEHOST value: nextcloud.home.keithjackson.dev - name: OVERWRITEPROTOCOL value: https - name: OVERWRITECLIURL value: https://nextcloud.home.keithjackson.dev exposure: public # edge port-forward + public DNS (docs/09; R-DNS/R-NET) egress: internet # normal WAN egress (docs/03; R-NET-05) — app store, integrity checks storage: - name: data size: 20Gi class: longhorn # ALL Nextcloud state (config/, data/, apps/, custom_apps/) on the mountPath: /var/www/html # 3-replica tier; irreplaceable, DR-critical (docs/04; R-STATE-02). # The whole html dir is persisted so config.php + user data survive a # rebuild (the default /data/ would strand them on ephemeral rootfs). dependencies: - to: nextcloud-db # explicit allow: Nextcloud -> its PostgreSQL (docs/13 graph; R-NET-02). port: 5432 # Renders the egress half; the DB namespace mirrors keycloak-db (no protocol: tcp # default-deny), so Cilium's default-allow accepts the reciprocal ingress. ingressRoutes: - host: nextcloud.home.keithjackson.dev port: 80 # apache HTTP; wildcard TLS terminates at the shared Gateway (docs/08/09) auth: mode: oidc # native Keycloak OIDC client (docs/13 SSO row, docs/15 "Native OIDC"; R-IDP-02) groups: - platform-admins # access scoped to an authorized group (R-IDP-06) # NOTE (OIDC follow-up + break-glass): like Gitea (docs/15 "Availability caveat"), Nextcloud keeps a # LOCAL admin as the break-glass path so an IdP outage never locks the operator out. At initial deploy # it comes up INSTALLED on that local admin (env above). The Keycloak `nextcloud` realm client + its # user_oidc app config is a DEFERRED follow-up: wiring it means editing the reconciled realm import in # platform-config (a malformed edit fails the whole platform-config apply / can leave the realm import # PENDING) AND post-install `occ` steps the image has no first-class env for — deferred rather than # risking the running Keycloak realm / Flux source (WS-APPS step 3 escape hatch). This records the # target integration; it embeds no secret. update: channel: stable # R-UPD-01 range: ">=31.0.0 <32.0.0" # stay on the 31.x stable line cadence: "0 4 * * *" autoRollbackOnFailedHealth: true # R-UPD-03 observability: metrics: true slis: - up # file-sync down is a critical alert (docs/10; R-OBS-01) backup: policy: daily-offcluster # DR-critical: data backed up off-cluster (docs/13, docs/04; R-STATE-03)