diff --git a/README.md b/README.md
index 381168f1a69c5aa94b48b7eab613c86c61c62693..39a66f04a9184ce61632fbc0f05031b0b8abd173 100644
--- a/README.md
+++ b/README.md
@@ -50,9 +50,19 @@ helm repo add nextcloud-onlyoffice https://open.greenhost.net/api/v4/projects/1/
 Then install the chart:
 
 ```console
-helm install -f values-local.yaml my-nextcloud nextcloud-onlyoffice/nextcloud-onlyoffice
+helm install --wait -f values-local.yaml my-nextcloud nextcloud-onlyoffice/nextcloud-onlyoffice
 ```
 
+**The `--wait` is important!** We need that because of how [helm chart
+hooks](https://helm.sh/docs/topics/charts_hooks/) work:
+
+> Note that if the --wait flag is set, the library will wait until all resources
+> are in a ready state and will not run the post-install hook until they are
+> ready.
+
+The job in this chart needs the Nextcloud pod to be in a ready state before
+being executed.
+
 ### Install from a local repo
 
 Start by cloning the nextcloud helm chart repo:
@@ -77,21 +87,27 @@ helm dependency build
 
 Then install the chart:
 ```console
-helm install -f values-local.yaml my-nextcloud .
+helm install --wait -f values-local.yaml my-nextcloud .
 ```
 
+**The `--wait` is important!** We need that because of how [helm chart
+hooks](https://helm.sh/docs/topics/charts_hooks/) work:
+
+> Note that if the --wait flag is set, the library will wait until all resources
+> are in a ready state and will not run the post-install hook until they are
+> ready.
+
+The job in this chart needs the Nextcloud pod to be in a ready state before
+being executed.
+
 ## Nextcloud configuration.
 
-This chart adds a "postStart" command to the Nextcloud pod, that installs apps
+This chart has a post-install/post-upgrade hook that installs apps
 (see below) and applies a custom configuration to set up those apps and
 integration with ONLYOFFICE as well as the Stackspin OIDC provider.
 
-Kubernetes postStart commands do not log to the pod log.
-Instead, the script creates its own log in `/var/www/tmp/postStart<date>.log`.
-This means that even if you can't `exec` into the pod (because something is failing),
-you can see the logs inside the `data` folder in the PVC.
-Often, if the `postStart` command fails,
-you can also see the problem by running `kubectl describe pod <nextcloud pod>`.
+The hook job needs the Nextcloud pod to be in a ready state before
+being executed.
 
 ## Apps
 
diff --git a/templates/job-setup-apps.yaml b/templates/job-setup-apps.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..993f2f5367fd279e1e6f9ecd1650a64fb8d0b5d2
--- /dev/null
+++ b/templates/job-setup-apps.yaml
@@ -0,0 +1,25 @@
+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:
+  template:
+    metadata:
+      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
+      serviceAccountName: {{ .Release.Name }}-setup-apps-job
+      containers:
+      - name: setup-apps-job
+        image: docker.io/bitnami/kubectl:1.25
+        command: ["kubectl", "exec", "deploy/{{ .Release.Name }}-nextcloud", "-n", {{ .Release.Namespace }}, "--", "/bin/bash", "/var/local/setup-apps.sh"]
diff --git a/templates/nextcloud-monitoring.yaml b/templates/nextcloud-monitoring.yaml
deleted file mode 100644
index 6fd197acdf0aaa06a3173da1fa37dce62d1f3550..0000000000000000000000000000000000000000
--- a/templates/nextcloud-monitoring.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-{{- if (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") }}
-apiVersion: monitoring.coreos.com/v1
-kind: PodMonitor
-metadata:
-  name: nextcloud
-  labels:
-    app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
-    app.kubernetes.io/name: nextcloud
-    app.kubernetes.io/instance: {{ .Release.Name | quote }}
-    helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
-spec:
-  namespaceSelector:
-    matchNames:
-    - stackspin-apps
-  podMetricsEndpoints:
-  - port: metrics
-  jobLabel: app.kubernetes.io/name
-  selector:
-    matchLabels:
-      app.kubernetes.io/component: app
-      app.kubernetes.io/instance: {{ .Release.Name | quote }}
-      app.kubernetes.io/name: nextcloud
----
-apiVersion: monitoring.coreos.com/v1
-kind: PrometheusRule
-metadata:
-  labels:
-    app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
-    app.kubernetes.io/name: nextcloud
-    app.kubernetes.io/instance: {{ .Release.Name | quote }}
-    helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
-  name: nextcloud
-spec:
-  groups:
-  - name: nextcloud
-    rules:
-    - alert: NextcloudSetupError
-      annotations:
-        message: The setup-apps.sh script of Nextcloud has encountered errors. See the postStart logs for more information.
-      expr: nextcloud_poststart_errors > 0
-      labels:
-        severity: warning
-{{- end }}
diff --git a/templates/nextcloud-onlyoffice-config.yaml b/templates/nextcloud-onlyoffice-config.yaml
index f8c22f73aca5c605d4d26faf037e5aaf5118a10b..b09774c89b814b2738f7c5c2ec94639a1c2a3c97 100644
--- a/templates/nextcloud-onlyoffice-config.yaml
+++ b/templates/nextcloud-onlyoffice-config.yaml
@@ -25,52 +25,6 @@ data:
     #   * Configures single-sign-on
     #   * Persists and loads the config.json config file
     #   * Updates database indices, columns, keys, etc needed after NC upgrade
-    #   * Writes a log to /var/www/tmp/postStart-<date>.log
-    set -e
-    exec > /var/www/tmp/postStart-$(date +"%s").log
-    exec 2> /var/www/tmp/postStart-$(date +"%s")_error.log
-
-    # Write a simple status (errors or no errors) to a file, to be served to
-    # prometheus by a sidecar container.
-    report_metrics() {
-      errors=$1
-      outfile=/srv/metrics/status
-      truncate -s 0 $outfile
-      echo '# HELP nextcloud_poststart_errors Whether the nextcloud postStart script has encountered errors.' >> $outfile
-      echo '# TYPE nextcloud_poststart_errors gauge' >> $outfile
-      echo "nextcloud_poststart_errors $errors" >> $outfile
-    }
-    # We just started, so no errors yet!
-    report_metrics "0"
-
-    exception_handler() {
-        signal=$1
-        exitCode=$2
-        lineNumber=$3
-        echo "setup-apps.sh received $signal (code $exitCode) on line $lineNumber"
-        if [ $signal == "EXIT" ] && [ $exitCode -eq 0 ]
-        then
-          # No problem, this is regular EXIT at the end of the script.
-          report_metrics "0"
-          echo "That's all good, exiting normally."
-        else
-          # Report to prometheus that we have an error.
-          report_metrics "1"
-          echo "Still exiting with status 0 to allow nextcloud to start."
-        fi
-        # Remove the handler for `EXIT` so we don't run that as well. If we're
-        # currently handling `EXIT` already then this is not necessary because
-        # bash treats an `exit` specially if it happens in the `EXIT` handler.
-        # If we're handling another signal though, then we want to prevent that
-        # the call to `exit` also triggers the `EXIT` handler.
-        trap '' EXIT
-        exit 0
-    }
-
-    trap 'exception_handler ERR $? $LINENO' ERR
-    trap 'exception_handler EXIT $? $LINENO' EXIT
-    trap 'exception_handler SIGINT $? $LINENO' SIGINT
-    trap 'exception_handler SIGTERM $? $LINENO' SIGTERM
 
     # Copied from the NC docker entrypoint to run OCC commands
     run_as() {
diff --git a/templates/rbac/role.yaml b/templates/rbac/role.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4d90b521b4321648d43c4527bfecd0ffc10ed15a
--- /dev/null
+++ b/templates/rbac/role.yaml
@@ -0,0 +1,16 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ .Release.Name }}-exec-in-pod
+  labels: 
+    app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
+    app.kubernetes.io/name: nextcloud
+    app.kubernetes.io/instance: {{ .Release.Name | quote }}
+    helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+rules:
+- apiGroups: ["apps"]
+  resources: ["deployments"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: [""]
+  resources: ["pods", "pods/exec"]
+  verbs: ["get", "list", "create"]
diff --git a/templates/rbac/rolebinding.yaml b/templates/rbac/rolebinding.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c9eaf63b4d158ffe65408ddf9c7a9decd1514e35
--- /dev/null
+++ b/templates/rbac/rolebinding.yaml
@@ -0,0 +1,17 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ .Release.Name }}-exec-in-pod
+  labels:
+    app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
+    app.kubernetes.io/name: nextcloud
+    app.kubernetes.io/instance: {{ .Release.Name | quote }}
+    helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+subjects:
+- kind: ServiceAccount
+  name: {{ .Release.Name }}-setup-apps-job
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  kind: Role
+  name: {{ .Release.Name }}-exec-in-pod
+  apiGroup: rbac.authorization.k8s.io
diff --git a/templates/rbac/serviceaccount.yaml b/templates/rbac/serviceaccount.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5a785fd335c188c24fdf34df4b12a8fbe2b4fc86
--- /dev/null
+++ b/templates/rbac/serviceaccount.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ .Release.Name }}-setup-apps-job
+  labels: 
+    app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
+    app.kubernetes.io/name: nextcloud
+    app.kubernetes.io/instance: {{ .Release.Name | quote }}
+    helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+
+
diff --git a/values.yaml b/values.yaml
index 37592eeb60ddc0a6b4b3dfbe7b2c8f46c2033e37..f3b376139a06761cdef7a26f7e21bb397626b561 100644
--- a/values.yaml
+++ b/values.yaml
@@ -37,28 +37,9 @@ nextcloud:
       - name: nextcloud-onlyoffice-config
         configMap:
           name: nextcloud-onlyoffice-config-and-scripts
-      - name: poststart-metrics
-        emptyDir:
-          medium: Memory
     extraVolumeMounts:
       - name: nextcloud-onlyoffice-config
         mountPath: /var/local
-      - name: poststart-metrics
-        mountPath: "/srv/metrics"
-    extraSidecarContainers:
-      - name: poststart-metrics
-        image: "weibeld/file-exporter:0.0.2"
-        ports:
-        - name: metrics
-          containerPort: 9872
-        volumeMounts:
-        - name: poststart-metrics
-          mountPath: "/srv/metrics"
-
-  lifecycle:
-    postStartCommand:
-      - "/bin/bash"
-      - "/var/local/setup-apps.sh"
 
 apps:
   default: