diff --git a/templates/_nextcloud-specs.tpl b/templates/_nextcloud-specs.tpl
deleted file mode 100644
index 2fc16754b3af62482c3c7467acf548bf8ba4bfb2..0000000000000000000000000000000000000000
--- a/templates/_nextcloud-specs.tpl
+++ /dev/null
@@ -1,95 +0,0 @@
-{{/* Change the user and group to www-data as required by occ */}}
-{{- define "nextcloud-onlyoffice.securityContext" }}
-fsGroup: 33
-runAsUser: 33
-runAsGroup: 33
-{{- end}}
-{{/* Add volume mounts that are also used by the nextcloud container */}}
-{{/* and the configMap that contains job specific content */}}
-{{- define "nextcloud-onlyoffice.volumeMounts" }}
-- name: nextcloud-data
-  mountPath: /var/www/
-  subPath: root
-- name: nextcloud-data
-  mountPath: /var/www/html
-  subPath: html
-- name: nextcloud-data
-  mountPath: /var/www/html/data
-  subPath: data
-- name: nextcloud-data
-  mountPath: /var/www/html/config
-  subPath: config
-- name: nextcloud-data
-  mountPath: /var/www/html/custom_apps
-  subPath: custom_apps
-- name: nextcloud-data
-  mountPath: /var/www/html/themes
-  subPath: themes
-- name: nextcloud-data
-  mountPath: /var/www/tmp
-  subPath: tmp
-- name: nextcloud-onlyoffice-config
-  mountPath: /var/local
-{{- end }}
-{{/* Set environment variables that are needed for the nextcloud setup */}}
-{{- define "nextcloud-onlyoffice.env" }}
-{{- if .Values.nextcloud.internalDatabase.enabled }}
-- name: SQLITE_DATABASE
-  value: {{ .Values.nextcloud.internalDatabase.name | quote }}
-{{- else if .Values.nextcloud.mariadb.enabled }}
-- name: MYSQL_HOST
-  value: {{ template "mariadb.primary.fullname" .Subcharts.nextcloud.Subcharts.mariadb }}
-- name: MYSQL_DATABASE
-  value: {{ .Values.nextcloud.mariadb.auth.database | quote }}
-- name: MYSQL_USER
-  valueFrom:
-    secretKeyRef:
-      name: {{ printf "%s-%s" .Release.Name "db" }}
-      key: db-username
-- name: MYSQL_PASSWORD
-  valueFrom:
-    secretKeyRef:
-      name: {{ printf "%s-%s" .Release.Name "db" }}
-      key: db-password
-{{- else }}
-- name: MYSQL_HOST
-  value: {{ .Values.nextcloud.externalDatabase.host | quote }}
-- name: MYSQL_DATABASE
-  value: {{ .Values.nextcloud.externalDatabase.database | quote }}
-- name: MYSQL_USER
-  valueFrom:
-    secretKeyRef:
-      name: {{ printf "%s-%s" .Release.Name "db" }}
-      key: db-username
-- name: MYSQL_PASSWORD
-  valueFrom:
-    secretKeyRef:
-      name: {{ printf "%s-%s" .Release.Name "db" }}
-      key: db-password
-{{- end }}
-- name: NEXTCLOUD_ADMIN_USER
-  valueFrom:
-    secretKeyRef:
-      name: {{ printf "%s-%s" .Release.Name "nextcloud" }}
-      key: nextcloud-username
-- name: NEXTCLOUD_ADMIN_PASSWORD
-  valueFrom:
-    secretKeyRef:
-      name: {{ printf "%s-%s" .Release.Name "nextcloud" }}
-      key: nextcloud-password
-- name: NEXTCLOUD_TRUSTED_DOMAINS
-  value: {{ .Values.nextcloud.nextcloud.host }}
-{{- end }}
-{{/* Add volumes that correspond to the volume mounts used in this tpl */}}
-{{- define "nextcloud-onlyoffice.volumes" }}
-- name: nextcloud-data
-{{- if .Values.nextcloud.persistence.enabled }}
-  persistentVolumeClaim:
-    claimName: {{ if .Values.nextcloud.persistence.existingClaim }}{{ .Values.nextcloud.persistence.existingClaim }}{{- else }}{{ template "nextcloud.fullname" .Subcharts.nextcloud }}-nextcloud{{- end }}
-{{- else }}
-  emptyDir: {}
-{{- end }}
-- name: nextcloud-onlyoffice-config
-  configMap:
-    name: {{ .Release.Name }}-nextcloud-onlyoffice-config
-{{- end}}
diff --git a/templates/job-configure-nextcloud.yaml b/templates/job-configure-nextcloud.yaml
deleted file mode 100644
index f40d132f9bf79b2a91a4d0b78c72ed5d9b14e8f0..0000000000000000000000000000000000000000
--- a/templates/job-configure-nextcloud.yaml
+++ /dev/null
@@ -1,34 +0,0 @@
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: "{{ .Release.Name }}-configure-nextcloud"
-  labels:
-    app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
-    app.kubernetes.io/instance: {{ .Release.Name | quote }}
-    helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
-  annotations:
-    "helm.sh/hook": post-install,post-upgrade
-    "helm.sh/hook-weight": "1"
-    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
-spec:
-  template:
-    metadata:
-      name: "{{.Release.Name}}-configure-nextcloud"
-      labels:
-        app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
-        app.kubernetes.io/instance: {{.Release.Name | quote }}
-        helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
-    spec:
-      restartPolicy: Never
-      securityContext: {{- include "nextcloud-onlyoffice.securityContext" . | indent 8 }}
-      containers:
-      - name: {{ .Release.Name }}-configure-nextcloud-job
-        image: {{ template "nextcloud.image" .Subcharts.nextcloud }}
-        command:
-          - "/usr/local/bin/php"
-          - "/var/www/html/occ"
-          - "config:import"
-          - "/var/local/config.json"
-        volumeMounts: {{- include "nextcloud-onlyoffice.volumeMounts" . | indent 8 }}
-        env: {{- include "nextcloud-onlyoffice.env" . | indent 8 }}
-      volumes: {{- include "nextcloud-onlyoffice.volumes" . | indent 6 }}
diff --git a/templates/job-setup-apps.yaml b/templates/job-setup-apps.yaml
deleted file mode 100644
index 30f6f97dc0289105f0ffc63539632556a5b3e3d2..0000000000000000000000000000000000000000
--- a/templates/job-setup-apps.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: "{{ .Release.Name }}-setup-apps"
-  labels:
-    app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
-    app.kubernetes.io/instance: {{ .Release.Name | quote }}
-    helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
-  annotations:
-    "helm.sh/hook": post-install,post-upgrade
-    "helm.sh/hook-weight": "0"
-spec:
-  backoffLimit: {{ .Values.setupApps.backoffLimit }}
-  ttlSecondsAfterFinished: 6000
-  template:
-    metadata:
-      name: "{{.Release.Name}}"
-      labels:
-        app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
-        app.kubernetes.io/instance: {{.Release.Name | quote }}
-        helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
-    spec:
-      restartPolicy: Never
-      securityContext: {{- include "nextcloud-onlyoffice.securityContext" . | indent 8 }}
-      containers:
-      - name: {{ .Release.Name }}-setup-apps-job
-        image: {{ template "nextcloud.image" .Subcharts.nextcloud }}
-        command:
-          - "/bin/bash"
-          - "/var/local/setup-apps.sh"
-        volumeMounts: {{- include "nextcloud-onlyoffice.volumeMounts" . | indent 8 }}
-        env: {{- include "nextcloud-onlyoffice.env" . | indent 8 }}
-      volumes: {{- include "nextcloud-onlyoffice.volumes" . | indent 6 }}
diff --git a/templates/nextcloud-onlyoffice-config.yaml b/templates/nextcloud-onlyoffice-config.yaml
index 1add29aeacde6b1021ce63602aeb1daf5ffac981..a52362c4cabf21beceae2d143506a9821f78cfbb 100644
--- a/templates/nextcloud-onlyoffice-config.yaml
+++ b/templates/nextcloud-onlyoffice-config.yaml
@@ -1,31 +1,15 @@
+---
 apiVersion: v1
 kind: ConfigMap
 metadata:
-  name: "{{ .Release.Name }}-nextcloud-onlyoffice-config"
+  # Can't use {{ .Release.name }} here, because we need to mount it to the
+  # Nextcloud pod from the values file
+  name: "nextcloud-onlyoffice-config-and-scripts"
   labels:
     app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
     app.kubernetes.io/instance: {{ .Release.Name | quote }}
     helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
 data:
-  onlyoffice-config.json: |
-    {
-      "apps": {
-        "onlyoffice": {
-          "DocumentServerInternalUrl": "",
-          "DocumentServerUrl": "https:\/\/{{ .Values.onlyoffice.server_name }}\/",
-          "StorageUrl": "https:\/\/{{ .Values.nextcloud.nextcloud.host }}\/",
-          "defFormats": "{\"csv\":\"false\",\"doc\":\"false\",\"docm\":\"false\",\"docx\":\"true\",\"dotx\":\"false\",\"epub\":\"false\",\"html\":\"false\",\"odp\":\"true\",\"ods\":\"true\",\"odt\":\"true\",\"pdf\":\"false\",\"potm\":\"false\",\"potx\":\"false\",\"ppsm\":\"false\",\"ppsx\":\"false\",\"ppt\":\"false\",\"pptm\":\"false\",\"pptx\":\"true\",\"rtf\":\"false\",\"txt\":\"false\",\"xls\":\"false\",\"xlsm\":\"false\",\"xlsx\":\"true\",\"xltm\":\"false\",\"xltx\":\"false\"}",
-          "editFormats": "{\"csv\":\"true\",\"odp\":\"true\",\"ods\":\"true\",\"odt\":\"true\",\"rtf\":\"false\",\"txt\":\"true\"}",
-          "enabled": "yes",
-          "groups": "[]",
-          "jwt_secret": "{{ .Values.onlyoffice.jwtSecret }}",
-          "sameTab": "false",
-          "settings_error": "",
-          "types": "filesystem",
-          "customizationForcesave": "true"
-        }
-      }
-    }
   setup-apps.sh: |
     #!/bin/bash
     #
@@ -38,21 +22,55 @@ data:
     #   * Runs upgrade routines after installation of a new release or new
     #     pinned apps.
     #   * Configures single-sign-on
-    #   * Persists and loads the onlyoffice-config.json config file
+    #   * Persists and loads the config.json config file
     #   * Updates database indices, columns, keys, etc needed after NC upgrade
+    exec 1>/var/www/html/data/postStart.log
+
+    # Copied from the NC docker entrypoint to run OCC commands
+    run_as() {
+        if [ "$(id -u)" = 0 ]; then
+            su -p "www-data" -s /bin/sh -c "$1"
+        else
+            sh -c "$1"
+        fi
+    }
+
+    echo "STARTING SETUP-APPS.SH"
 
     set -ev
 
     # Debug: place the json file in a persistent location for reuse
-    cp /var/local/onlyoffice-config.json /var/www/html/
+    cp /var/local/config.json /var/www/html/
 
     occ="/var/www/html/occ"
 
+    # There's a nextcloud setup process. First, wait for `occ` to exist
+    until [ -e $occ ]; do
+        echo "$occ doesn't exist yet..."
+        sleep 1
+    done
+
+    echo "$occ now exists!!!"
+    lock=/var/www/html/nextcloud-init-sync.lock
+
+    # If Nextcloud is still installing files at this point, a "lock file" will
+    # exist, wait until that's gone too before running our own setup:
+    until [ ! -f "$lock" ]
+    do
+        echo "Nextcloud lock file $lock still exists..."
+        sleep 1
+    done
+
+    echo "Nextcloud lock file $lock is gone, we can do our thing!"
 
     # Enable app store so we can run `install` and `enable` commands
-    php $occ config:system:set appstoreenabled --type boolean --value true
+    run_as "php $occ config:system:set appstoreenabled --type boolean --value true"
 
-    app_versions=$(php occ app:list --output json)
+    echo "app store enabled"
+
+    app_versions=$(run_as "php $occ app:list --output json")
+
+    echo "app versions found"
 
     # Install all apps declared in the `apps` helm values array
     {{- range .Values.apps }}
@@ -89,39 +107,50 @@ data:
     fi
     {{- else }}
     # Unpinned app
-    if ! echo $app_versions | grep -q '"{{ .name }}"'; then
+    if ! echo "$app_versions" | grep -q '"{{ .name }}"'; then
         echo "Installing app {{ .name }}"
-        php $occ app:install {{ .name }} --keep-disabled --no-interaction
+        run_as "php $occ app:install {{ .name }} --keep-disabled --no-interaction"
     else
         # Update the app to its latest version
         echo "Updating app {{ .name }}"
-        php $occ app:update {{ .name }} --no-interaction
+        run_as "php $occ app:update {{ .name }} --no-interaction"
     fi
     {{ end }} # end if and .github_repository .version
     {{- if .enabled }}
     # Enable {{ .name }} app
-    php $occ app:enable {{ .name }}
+    run_as "php $occ app:enable {{ .name }}"
     {{ end }} # end if .enabled
     {{ end }} # end range .Values.apps
 
     # Some of the manually installed apps might need to run upgrade scripts, run
     # them now
-    php $occ upgrade
+    run_as "php $occ upgrade"
+
 
     # Config settings from the configmap above
-    php $occ config:import /var/local/onlyoffice-config.json
-    php $occ config:app:set sociallogin custom_providers --value='{"custom_oidc": [{{ .Values.sociallogin.custom_oidc | toJson }}]}'
-    php $occ config:app:set sociallogin auto_create_groups --value='{{ .Values.sociallogin.auto_create_groups }}'
-    php $occ config:app:set sociallogin update_profile_on_login --value='{{ .Values.sociallogin.update_profile_on_login }}'
+    run_as "php $occ config:import /var/local/config.json"
+
+    echo "Setting custom OIDC provider data"
+
+    # Because of escape hell we can't use run_as here (unless you have amazing
+    # bash-fu)
+    su -p "www-data" -s /bin/bash -c "php $occ config:app:set sociallogin custom_providers --value='"'{"custom_oidc": [{{ .Values.sociallogin.custom_oidc | toJson }}]}'"'"
+
+    echo "Setting other sociallogin data"
+
+    run_as "php $occ config:app:set sociallogin auto_create_groups --value='{{ .Values.sociallogin.auto_create_groups }}'"
+    run_as "php $occ config:app:set sociallogin update_profile_on_login --value='{{ .Values.sociallogin.update_profile_on_login }}'"
+
+    echo "disabling app store"
 
     # Disable app store again
-    php $occ config:system:set appstoreenabled --type boolean --value false
+    run_as "php $occ config:system:set appstoreenabled --type boolean --value false"
 
-    # Update database indices, columns, keys, etc needed after NC upgrade
-    php $occ db:add-missing-indices --no-interaction
-    php $occ db:add-missing-columns --no-interaction
-    php $occ db:add-missing-primary-keys --no-interaction
-    php $occ db:convert-filecache-bigint --no-interaction
+    echo "Updating database indices, columns, keys, etc."
+    run_as "php $occ db:add-missing-indices --no-interaction"
+    run_as "php $occ db:add-missing-columns --no-interaction"
+    run_as "php $occ db:add-missing-primary-keys --no-interaction"
+    run_as "php $occ db:convert-filecache-bigint --no-interaction"
 
   #
   # All values in config.json are applied by the nextcloud occ command
@@ -149,7 +178,18 @@ data:
                 "backgroundjobs_mode": "webcron"
             },
             "onlyoffice":{
-                "sameTab": "true"
+                "DocumentServerInternalUrl": "",
+                "DocumentServerUrl": "https:\/\/{{ .Values.onlyoffice.server_name }}\/",
+                "StorageUrl": "https:\/\/{{ .Values.nextcloud.nextcloud.host }}\/",
+                "defFormats": "{\"csv\":\"false\",\"doc\":\"false\",\"docm\":\"false\",\"docx\":\"true\",\"dotx\":\"false\",\"epub\":\"false\",\"html\":\"false\",\"odp\":\"true\",\"ods\":\"true\",\"odt\":\"true\",\"pdf\":\"false\",\"potm\":\"false\",\"potx\":\"false\",\"ppsm\":\"false\",\"ppsx\":\"false\",\"ppt\":\"false\",\"pptm\":\"false\",\"pptx\":\"true\",\"rtf\":\"false\",\"txt\":\"false\",\"xls\":\"false\",\"xlsm\":\"false\",\"xlsx\":\"true\",\"xltm\":\"false\",\"xltx\":\"false\"}",
+                "editFormats": "{\"csv\":\"true\",\"odp\":\"true\",\"ods\":\"true\",\"odt\":\"true\",\"rtf\":\"false\",\"txt\":\"true\"}",
+                "enabled": "yes",
+                "groups": "[]",
+                "jwt_secret": "{{ .Values.onlyoffice.jwtSecret }}",
+                "sameTab": "true",
+                "settings_error": "",
+                "types": "filesystem",
+                "customizationForcesave": "true"
             }
         }
     }
diff --git a/values.yaml b/values.yaml
index 041fd1ac93fc7bf0a5ffe9ca92e439111e50b39f..97d7a88a1625c72789880fbe2c47ebba128c2986 100644
--- a/values.yaml
+++ b/values.yaml
@@ -32,6 +32,21 @@ nextcloud:
     enabled: true
     failureThreshold: 60
 
+  nextcloud:
+    extraVolumes:
+      - name: nextcloud-onlyoffice-config
+        configMap:
+          name: nextcloud-onlyoffice-config-and-scripts
+
+    extraVolumeMounts:
+      - name: nextcloud-onlyoffice-config
+        mountPath: /var/local
+
+  lifecycle:
+    postStartCommand:
+      - "/bin/bash"
+      - "/var/local/setup-apps.sh"
+
 apps:
   - name: sociallogin
     # apps[0].enabled needs to be set to true if you want to enable login via an external