Repository: Squidex/squidex
Pull request #1211: Helm Chart Security Enhancements and Feature Additions
Author: login: sinadarbouy
Created: 2025-04-12T17:25:13Z | Merged: 2025-04-28T10:21:38Z

## Overview
This PR enhances the Squidex Helm chart with security improvements and additional features to provide better deployment flexibility and security posture. The changes include security hardening measures and new Kubernetes features support.

## Key Changes

### Security Enhancements
- 🔒 Enable `runAsNonRoot` by default for better security
- 🛡️ Add Network Policies support for controlled pod communication
- 🔐 Set default logging level to `Warning` to prevent accidental secret exposure in logs
- 🚫 Change container port to 8080 to avoid privileged ports (0-1024)

### Feature Additions
- 📈 Add Horizontal Pod Autoscaling (HPA) support
- 🔄 Add Pod Disruption Budget (PDB) support
- 🎯 Add deployment strategy configuration with RollingUpdate
- 🏷️ Support for custom annotations, commands, and args
- 🔄 Support separate replicaCount for worker pods
- 📝 Add support for revisionHistoryLimit

### Configuration Improvements
- 🆕 Update app version to 7.18.0
- 🏷️ Fix labels parsing issue when adding custom labels
- 🎯 Add default resource limits and requests
- 🌐 Add default affinity rules for better pod distribution
- 🔧 Add default nginx annotations for proxy configurations
- 📦 Add missing values in values.yaml

## Breaking Changes
Several default values in values.yaml have been modified to enhance security:

1. **Container Port**: Changed from 80 to 8080
   - Impact: If you're directly referencing port 80 in your configurations, you'll need to update them
   - Migration: Update your service/ingress configurations to use port 8080

2. **Security Context**:
   - `runAsNonRoot` is now true by default
   - Added default security context configurations for pods and containers
   - Impact: Pods will now run as non-root by default
   - Migration: If your application requires root access, explicitly set `runAsNonRoot: false`

3. **Logging Level**:
   - Changed from INFORMATION to Warning
   - Impact: Less verbose logging by default
   - Migration: Set `LOGGING__LEVEL: INFORMATION` if you need detailed logs

4. **Network Policies**:
   - Enabled by default
   - Impact: Pod communication is restricted by default
   - Migration: Disable network policies or customize rules if needed

5. **Resource Requirements**:
   - Added default resource limits and requests
   - Impact: Pods will have resource constraints by default
   - Migration: Adjust resource values according to your needs

## Testing Done
- Tested with kube-linter for security best practices
- Tested HPA functionality
- Verified network policies
- Tested custom annotations and commands injection

## Documentation
- Updated README.md with new parameters
- Added documentation for all new features
- Updated values.yaml with detailed comments

## Checklist
- [x] Updated Chart version to 1.0.4
- [x] Updated app version to 7.18.0
- [x] Added/updated documentation
- [x] Tested all new features
- [x] Ran kube-linter checks

## Related Issues
None

## Notes
The default configuration now follows Kubernetes security best practices while maintaining flexibility for customization through values.yaml.


Diff:
diff --git a/helm/squidex7/Chart.yaml b/helm/squidex7/Chart.yaml
index f0e0de6e4d..f636c85800 100644
--- a/helm/squidex7/Chart.yaml
+++ b/helm/squidex7/Chart.yaml
@@ -5,7 +5,7 @@ name: squidex7
 icon: https://raw.githubusercontent.com/Squidex/squidex/master/media/logo-squared.png
 description: Squidex CMS v7.0 and newer
 
-version: 2.0.0
+version: 2.0.1
 appVersion: "7.18.0"
 
 home: https://squidex.io/
diff --git a/helm/squidex7/README.md b/helm/squidex7/README.md
index 1aa4d3adb1..944064a33e 100644
--- a/helm/squidex7/README.md
+++ b/helm/squidex7/README.md
@@ -46,17 +46,34 @@ The command removes all the Kubernetes components associated with the chart and
 
 ### Global parameters
 
-| Name                       | Description                    | Value             |
-| -------------------------- | ------------------------------ | ----------------- |
-| `service.type`             | Kubernetes Service type        | `ClusterIP`       |
-| `service.port`             | Kubernetes Service port        | `80`              |
-| `deployment.replicaCount`  | Number of instances.           | `1`               |
-| `image.repository`         | Squidex image registry         | `squidex/squidex` |
-| `image.pullPolicy`         | Squidex image pull policy      | `IfNotPresent`    |
-| `runAsNonRoot`             |                                | `false`           |
-| `ingress.enabled`          | True to deploy an ingress      | `true`            |
-| `ingress.ingressClassName` | The ingress class.             | `nginx`           |
-| `ingress.hostName`         | The host name for the ingress. | `squidex.local`   |
+| Name                                               | Description                                                         | Value             |
+| -------------------------------------------------- | ------------------------------------------------------------------- | ----------------- |
+| `nameOverride`                                     | Override the name of the application.                               | `squidex`         |
+| `labels`                                           | Labels to add to the deployment                                     | `{}`              |
+| `service.type`                                     | Kubernetes Service type                                             | `ClusterIP`       |
+| `service.port`                                     | Kubernetes Service port                                             | `8080`            |
+| `deployment.replicaCount`                          | Number of replicas (ignored if autoscaling enabled)                 | `3`               |
+| `deployment.worker.replicaCount`                   | Number of worker instances                                          | `1`               |
+| `deployment.revisionHistoryLimit`                  | Number of revision history                                          | `2`               |
+| `deployment.serviceAccountName`                    | Name of the service account to use                                  | `""`              |
+| `deployment.strategy.type`                         | Deployment strategy type                                            | `RollingUpdate`   |
+| `deployment.strategy.rollingUpdate.maxSurge`       | Maximum number of pods that can be created above the desired amount | `1`               |
+| `deployment.strategy.rollingUpdate.maxUnavailable` | Maximum number of unavailable pods during update                    | `0`               |
+| `deployment.restartPolicy`                         | Pod restart policy                                                  | `Always`          |
+| `deployment.annotations`                           | Annotations to add to the deployment                                | `nil`             |
+| `deployment.command`                               | Command to run in the container                                     | `nil`             |
+| `deployment.args`                                  | Arguments to pass to the container                                  | `nil`             |
+| `networkPolicy.enabled`                            | Enable network policies                                             | `true`            |
+| `image.repository`                                 | Squidex image registry                                              | `squidex/squidex` |
+| `image.pullPolicy`                                 | Squidex image pull policy                                           | `IfNotPresent`    |
+| `resources`                                        | Resource requests and limits                                        | `{}`              |
+| `topologySpreadConstraints`                        | Topology spread constraints for pod scheduling                      | `[]`              |
+| `priorityClassName`                                | Priority class name for the pod                                     | `nil`             |
+| `runAsNonRoot`                                     | Run container as non-root user.                                     | `true`            |
+| `ingress.enabled`                                  | True to deploy an ingress                                           | `true`            |
+| `ingress.ingressClassName`                         | The ingress class.                                                  | `nginx`           |
+| `ingress.annotations`                              | Ingress annotations                                                 | `{}`              |
+| `ingress.hostName`                                 | The host name for the ingress.                                      | `squidex.local`   |
 
 ### Squidex parameters
 
@@ -90,7 +107,7 @@ The command removes all the Kubernetes components associated with the chart and
 | `env.LOGGING__APPLICATIONINSIGHTS__CONNECTIONSTRING` | The connection string to application insights.                                                                   | `nil`                        |
 | `env.LOGGING__COLORS`                                | Use colors in the console output.                                                                                | `false`                      |
 | `env.LOGGING__HUMAN`                                 | Setting the flag to true, enables well formatteds json logs.                                                     | `false`                      |
-| `env.LOGGING__LEVEL`                                 | Trace, Debug, Information, Warning, Error, Fatal                                                                 | `INFORMATION`                |
+| `env.LOGGING__LEVEL`                                 | Trace, Debug, Information, Warning, Error, Fatal                                                                 | `Warning`                    |
 | `env.LOGGING__LOGREQUESTS`                           | Set to false to disable logging of http requests.                                                                | `true`                       |
 | `env.LOGGING__OTLP__ENABLED`                         | True, to enable OpenTelemetry Protocol integration                                                               | `false`                      |
 | `env.LOGGING__OLTP__ENDPOINT`                        | The endpoint to the agent                                                                                        | `nil`                        |
@@ -101,7 +118,13 @@ The command removes all the Kubernetes components associated with the chart and
 | `env.STORE__MONGODB__CONTENTDATABASE`                | The name of the database for content items.                                                                      | `SquidexContent`             |
 | `env.URLS__BASEURL`                                  | Set the base url of your application, to generate correct urls in background process.                            | `https://squidex.local/`     |
 | `env.URLS__ENFORCEHTTPS`                             | Set it to true to redirect the user from http to https permanently                                               | `false`                      |
-| `env.ASPNETCORE_URLS`                                | An override to ensure that kestrel starts on a non-privileged port                                               | `http://+:80`                |
+| `env.ASPNETCORE_URLS`                                | An override to ensure that kestrel starts on a non-privileged port                                               | `http://+:8080`              |
+| `autoscaling.enabled`                                | Enable autoscaling for the deployment                                                                            | `true`                       |
+| `autoscaling.maxReplicas`                            | Maximum number of replicas                                                                                       | `6`                          |
+| `autoscaling.minReplicas`                            | Minimum number of replicas                                                                                       | `3`                          |
+| `autoscaling.targetCPUUtilizationPercentage`         | Target CPU utilization percentage                                                                                | `85`                         |
+| `podDisruptionBudget.minAvailable`                   | Minimum number of available pods                                                                                 | `1`                          |
+| `podDisruptionBudget.unhealthyPodEvictionPolicy`     | Policy for evicting unhealthy pods                                                                               | `AlwaysAllow`                |
 
 ### MongoDB parameters
 
@@ -124,4 +147,4 @@ Parameters are generated with: https://github.com/bitnami-labs/readme-generator-
 
 ## Support
 
-Use the support forum to get help: https://support.squidex.io
\ No newline at end of file
+Use the support forum to get help: https://support.squidex.io
diff --git a/helm/squidex7/templates/_helpers.tpl b/helm/squidex7/templates/_helpers.tpl
index 05e2e95e5d..9ac7f273b4 100644
--- a/helm/squidex7/templates/_helpers.tpl
+++ b/helm/squidex7/templates/_helpers.tpl
@@ -19,7 +19,8 @@ app.kubernetes.io/version: {{ .Values.selectors.version | quote }}
 helm.sh/chart: {{ include "squidex.chart" . }}
 app.kubernetes.io/managed-by: {{ .Release.Service }}
 {{- if .Values.labels }}
-{{- toYaml .Values.labels | nindent 4 }}
+{{- "\n" -}}
+{{- toYaml .Values.labels }}
 {{- end -}}
 {{- end -}}
 
@@ -70,4 +71,4 @@ If release name contains chart name it will be used as a full name.
 {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
 {{- end -}}
 {{- end -}}
-{{- end -}}
\ No newline at end of file
+{{- end -}}
diff --git a/helm/squidex7/templates/deployment-worker.yaml b/helm/squidex7/templates/deployment-worker.yaml
index 625b3acb06..9bd8a79fa3 100644
--- a/helm/squidex7/templates/deployment-worker.yaml
+++ b/helm/squidex7/templates/deployment-worker.yaml
@@ -6,7 +6,10 @@ metadata:
     {{- include "squidex.labels" . | indent 4 }}
     app.kubernetes.io/role: worker
 spec:
-  replicas: 1
+  replicas: {{ .Values.deployment.worker.replicaCount }}
+  revisionHistoryLimit: {{ .Values.deployment.revisionHistoryLimit }}
+  strategy:
+    {{- toYaml .Values.deployment.strategy | nindent 4 }}
   selector:
     matchLabels:
       {{- include "squidex.selectors" . | indent 6 }}
@@ -16,6 +19,10 @@ spec:
       labels:
         {{- include "squidex.selectors" . | indent 8 }}
         app.kubernetes.io/role: worker
+      {{- if .Values.deployment.annotations }}
+      annotations:
+        {{- toYaml .Values.deployment.annotations | nindent 8 }}
+      {{- end }}
     spec:
       {{- with .Values.imagePullSecrets }}
       imagePullSecrets:
@@ -25,6 +32,7 @@ spec:
       securityContext:
         {{- toYaml .Values.podSecurityContext | nindent 8 }}
       {{- end }}
+      restartPolicy: {{ .Values.deployment.restartPolicy }}
       containers:
         - name: {{ .Chart.Name }}
           image: "{{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag }}"
@@ -33,9 +41,17 @@ spec:
           securityContext:
             {{- toYaml .Values.containerSecurityContext | nindent 12 }}
           {{- end }}
+          {{- if .Values.deployment.command }}
+          command:
+            {{- toYaml .Values.deployment.command | nindent 12 }}
+          {{- end }}
+          {{- if .Values.deployment.args }}
+          args:
+            {{- toYaml .Values.deployment.args | nindent 12 }}
+          {{- end }}
           ports:
             - name: http
-              containerPort: 80
+              containerPort: 8080
               protocol: TCP
           livenessProbe:
             httpGet:
@@ -58,7 +74,6 @@ spec:
               value: {{ $val | quote }}
             {{- end }}
           {{- end }}
-
             - name: CLUSTERING__WORKER
               value: "true"
           
@@ -85,4 +100,4 @@ spec:
         {{- toYaml .Values.tolerations | nindent 8 }}
       {{- if (.Values.deployment.serviceAccountName) }}
       serviceAccountName: {{ .Values.deployment.serviceAccountName}}
-      {{- end }}
\ No newline at end of file
+      {{- end }}
diff --git a/helm/squidex7/templates/deployment.yaml b/helm/squidex7/templates/deployment.yaml
index 67e89f028e..28e382f2a0 100644
--- a/helm/squidex7/templates/deployment.yaml
+++ b/helm/squidex7/templates/deployment.yaml
@@ -6,7 +6,12 @@ metadata:
     {{- include "squidex.labels" . | indent 4 }}
     app.kubernetes.io/role: api
 spec:
+  {{- if not .Values.autoscaling.enabled }}
   replicas: {{ .Values.deployment.replicaCount }}
+  {{- end }}
+  revisionHistoryLimit: {{ .Values.deployment.revisionHistoryLimit }}
+  strategy:
+    {{- toYaml .Values.deployment.strategy | nindent 4 }}
   selector:
     matchLabels:
       {{- include "squidex.selectors" . | indent 6 }}
@@ -16,6 +21,10 @@ spec:
       labels:
         {{- include "squidex.selectors" . | indent 8 }}
         app.kubernetes.io/role: api
+      {{- if .Values.deployment.annotations }}
+      annotations:
+        {{- toYaml .Values.deployment.annotations | nindent 8 }}
+      {{- end }}
     spec:
       {{- with .Values.imagePullSecrets }}
       imagePullSecrets:
@@ -25,6 +34,10 @@ spec:
       securityContext:
         {{- toYaml .Values.podSecurityContext | nindent 8 }}
       {{- end }}
+      restartPolicy: {{ .Values.deployment.restartPolicy }}
+      {{- if .Values.priorityClassName }}
+      priorityClassName: {{ .Values.priorityClassName }}
+      {{- end }}
       containers:
         - name: {{ .Chart.Name }}
           image: "{{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag }}"
@@ -33,9 +46,17 @@ spec:
           securityContext:
             {{- toYaml .Values.containerSecurityContext | nindent 12 }}
           {{- end }}
+          {{- if .Values.deployment.command }}
+          command:
+            {{- toYaml .Values.deployment.command | nindent 12 }}
+          {{- end }}
+          {{- if .Values.deployment.args }}
+          args:
+            {{- toYaml .Values.deployment.args | nindent 12 }}
+          {{- end }}
           ports:
             - name: http
-              containerPort: 80
+              containerPort: 8080
               protocol: TCP
           livenessProbe:
             httpGet:
@@ -58,7 +79,6 @@ spec:
               value: {{ $val | quote }}
             {{- end }}
           {{- end }}
-
             - name: CLUSTERING__WORKER
               value: "false"
           
@@ -81,8 +101,12 @@ spec:
         {{- toYaml .Values.nodeSelector | nindent 8 }}
       affinity:
         {{- toYaml .Values.affinity | nindent 8 }}
+      {{- if .Values.topologySpreadConstraints }}
+      topologySpreadConstraints:
+        {{- toYaml .Values.topologySpreadConstraints | nindent 8 }}
+      {{- end }}
       tolerations:
         {{- toYaml .Values.tolerations | nindent 8 }}
       {{- if (.Values.deployment.serviceAccountName) }}
       serviceAccountName: {{ .Values.deployment.serviceAccountName}}
-      {{- end }}
\ No newline at end of file
+      {{- end }}
diff --git a/helm/squidex7/templates/hpa.yaml b/helm/squidex7/templates/hpa.yaml
new file mode 100644
index 0000000000..3023797e56
--- /dev/null
+++ b/helm/squidex7/templates/hpa.yaml
@@ -0,0 +1,14 @@
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v1
+kind: HorizontalPodAutoscaler
+metadata:
+  name: {{ include "squidex.fullname" . }}
+spec:
+  maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+  minReplicas: {{ .Values.autoscaling.minReplicas }}
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: {{ include "squidex.fullname" . }}
+  targetCPUUtilizationPercentage: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+{{- end }}
diff --git a/helm/squidex7/templates/ingress.yaml b/helm/squidex7/templates/ingress.yaml
index 42a5dfffaf..5c9ed95e1d 100644
--- a/helm/squidex7/templates/ingress.yaml
+++ b/helm/squidex7/templates/ingress.yaml
@@ -34,4 +34,4 @@ spec:
                 name: {{ $fullName }}
                 port:
                   number: {{ .Values.service.port }}
-{{- end -}}
\ No newline at end of file
+{{- end -}}
diff --git a/helm/squidex7/templates/networkpolicy.yaml b/helm/squidex7/templates/networkpolicy.yaml
new file mode 100644
index 0000000000..c49cdaecd1
--- /dev/null
+++ b/helm/squidex7/templates/networkpolicy.yaml
@@ -0,0 +1,19 @@
+{{- if .Values.networkPolicy.enabled }}
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-{{ include "squidex.fullname" . }}
+  labels:
+    {{- include "squidex.labels" . | indent 4 }}
+spec:
+  podSelector:
+    matchLabels:
+      {{- include "squidex.selectors" . | indent 6 }}
+  policyTypes:
+  - Ingress
+  - Egress
+  ingress:
+    {{- toYaml .Values.networkPolicy.ingressRules | nindent 4 }}
+  egress:
+    {{- toYaml .Values.networkPolicy.egressRules | nindent 4 }}
+{{- end }} 
diff --git a/helm/squidex7/templates/pdb.yaml b/helm/squidex7/templates/pdb.yaml
new file mode 100644
index 0000000000..de2ab7d21c
--- /dev/null
+++ b/helm/squidex7/templates/pdb.yaml
@@ -0,0 +1,20 @@
+{{- if .Values.podDisruptionBudget }}
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ include "squidex.fullname" . }}
+  labels:
+  {{- include "squidex.labels" . | indent 4 }}
+spec:
+  {{- if .Values.podDisruptionBudget.minAvailable }}
+  minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
+  {{- end }}
+  {{- if .Values.podDisruptionBudget.maxUnavailable }}
+  maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
+  {{- end }}
+  unhealthyPodEvictionPolicy: {{ .Values.podDisruptionBudget.unhealthyPodEvictionPolicy }}
+  selector:
+    matchLabels:
+      {{- include "squidex.selectors" . | indent 6 }}
+      app.kubernetes.io/role: api
+{{- end }}
diff --git a/helm/squidex7/templates/service.yaml b/helm/squidex7/templates/service.yaml
index d483522daa..844d75af53 100644
--- a/helm/squidex7/templates/service.yaml
+++ b/helm/squidex7/templates/service.yaml
@@ -14,4 +14,4 @@ spec:
       name: http
   selector:
     {{- include "squidex.selectors" . | indent 4 }}
-    app.kubernetes.io/role: api
\ No newline at end of file
+    app.kubernetes.io/role: api
diff --git a/helm/squidex7/values.yaml b/helm/squidex7/values.yaml
index cdc56161a4..678b195e9f 100644
--- a/helm/squidex7/values.yaml
+++ b/helm/squidex7/values.yaml
@@ -1,18 +1,85 @@
 ## @section Global parameters
 
-## @skip labels
+## @param nameOverride Override the name of the application.
+nameOverride: "squidex"
+
+## @param labels [object] Labels to add to the deployment
 labels:
+  # custom: "custom"
+
 service:
   ## @param service.type Kubernetes Service type
   ##
   type: ClusterIP
   ## @param service.port Kubernetes Service port
   ##
-  port: 80
+  port: 8080
+
 deployment:
-  ## @param deployment.replicaCount Number of instances.
-  ##
-  replicaCount: 1
+  ## @param deployment.replicaCount Number of replicas (ignored if autoscaling enabled)
+  replicaCount: 3
+  worker:
+    ## @param deployment.worker.replicaCount Number of worker instances
+    replicaCount: 1 # only one worker supported
+  ## @param deployment.revisionHistoryLimit [default: 2] Number of revision history
+  revisionHistoryLimit: 2
+  ## @param deployment.serviceAccountName Name of the service account to use
+  serviceAccountName: ""
+  ## @param deployment.strategy.type Deployment strategy type
+  strategy:
+    type: RollingUpdate
+    ## @param deployment.strategy.rollingUpdate.maxSurge Maximum number of pods that can be created above the desired amount
+    rollingUpdate:
+      maxSurge: 1
+      ## @param deployment.strategy.rollingUpdate.maxUnavailable Maximum number of unavailable pods during update
+      maxUnavailable: 0
+  ## @param deployment.restartPolicy Pod restart policy
+  restartPolicy: Always
+  ## @param deployment.annotations Annotations to add to the deployment
+  annotations:
+    # vault.hashicorp.com/agent-pre-populate-only: "true"
+    # vault.hashicorp.com/agent-limits-cpu: 50m
+    # vault.hashicorp.com/agent-limits-mem: 64Mi
+    # vault.hashicorp.com/agent-requests-cpu: 10m
+    # vault.hashicorp.com/agent-requests-mem: 16Mi
+  ## @param deployment.command Command to run in the container
+  command:
+    # - sh
+    # - -c
+  ## @param deployment.args Arguments to pass to the container
+  args:
+    # - 'dotnet Squidex.dll'
+
+## @param networkPolicy.enabled Enable network policies
+networkPolicy:
+  enabled: true
+  ## @skip networkPolicy.ingressRules
+  ingressRules:
+    - from:
+        - namespaceSelector:
+            matchLabels:
+              kubernetes.io/metadata.name: ingress-nginx
+        - podSelector:
+            matchLabels:
+              app.kubernetes.io/instance: ingress-nginx
+      ports:
+        - port: 8080
+          protocol: TCP
+  ## @skip networkPolicy.egressRules
+  egressRules:
+    - to:
+      - namespaceSelector:
+          matchLabels:
+            kubernetes.io/metadata.name: kube-system
+        podSelector:
+          matchLabels:
+            k8s-app: kube-dns
+      ports:
+        - port: 53
+          protocol: UDP
+        - port: 53
+          protocol: TCP
+
 selectors:
   ## @skip selectors.component
   ##
@@ -31,21 +98,56 @@ image:
   ##
   pullPolicy: IfNotPresent
 
-## @skip resources
-resources: { }
+## @param resources [object] Resource requests and limits
+resources:
+  limits:
+    memory: "1Gi"
+  requests:
+    cpu: "200m"
+    memory: "512Mi"
 ## @skip nodeSelector
 nodeSelector: { }
 ## @skip tolerations
 tolerations: [ ]
 ## @skip affinity
-affinity: { }
+affinity:
+  podAntiAffinity:
+    preferredDuringSchedulingIgnoredDuringExecution:
+    - weight: 100
+      podAffinityTerm:
+        labelSelector:
+          matchLabels:
+            app.kubernetes.io/instance: squidex
+            app.kubernetes.io/component: squidex
+        topologyKey: kubernetes.io/hostname
+  nodeAffinity:
+    requiredDuringSchedulingIgnoredDuringExecution:
+      nodeSelectorTerms:
+      - matchExpressions:
+        - key: kubernetes.io/arch
+          operator: In
+          values:
+          - amd64
+          - arm64
+
+## @param topologySpreadConstraints [array] Topology spread constraints for pod scheduling
+topologySpreadConstraints:
+  # - maxSkew: 1
+  #   topologyKey: kubernetes.io/hostname
+  #   whenUnsatisfiable: DoNotSchedule
+  #   labelSelector:
+  #     matchLabels:
+  #       app.kubernetes.io/instance: squidex
+  #       app.kubernetes.io/component: squidex
+
+## @param priorityClassName [nullable] Priority class name for the pod
+priorityClassName:
 
 ## @skip clusterSuffix
 clusterSuffix: cluster.local
 
-## @param runAsNonRoot
-## Set to true to run Squidex as nonroot. Defaults to false for backwards compatibility.
-runAsNonRoot: false
+## @param runAsNonRoot Run container as non-root user.
+runAsNonRoot: true
 
 ## @skip podSecurityContext - object - optional
 ## You can modify the security context used to run PODS in the cluster
@@ -63,6 +165,7 @@ podSecurityContext:
 ## @skip containerSecurityContext - object - optional
 ## You can modify the security context used to run CONTAINERS in the cluster
 ## For information regarding which settings are required per policy see: https://kubernetes.io/docs/concepts/security/pod-security-standards/
+## readOnlyRootFilesystem: true not supported becasue of backup and restore process
 ## An example that follows the Restricted profile is described below:
 #
 containerSecurityContext:
@@ -84,10 +187,15 @@ ingress:
   enabled: true
   ## @param ingress.ingressClassName The ingress class.
   ingressClassName: nginx
-  ## Squidex Ingress annotations
-  # annotations:
-  #   kubernetes.io/ingress.class: nginx
-  #   kubernetes.io/tls-acme: "true"
+  ## @param ingress.annotations [object] Ingress annotations
+  annotations:
+    #   kubernetes.io/ingress.class: nginx
+    #   kubernetes.io/tls-acme: "true"
+    nginx.ingress.kubernetes.io/proxy-body-size: 50m
+    nginx.ingress.kubernetes.io/proxy-buffer-size: 128k
+    nginx.ingress.kubernetes.io/proxy-buffers: 4 256k
+    nginx.ingress.kubernetes.io/proxy-busy-buffers-size: 256k
+    nginx.ingress.kubernetes.io/ssl-redirect: 'true'
   ## @param ingress.hostName The host name for the ingress.
   ## 
   hostName: squidex.local
@@ -119,7 +227,7 @@ env:
   IDENTITY__ADMINPASSWORD: ""
   ## @param env.IDENTITY__ADMINRECREATE Recreate the admin if it does not exist or the password does not match
   ##
-  IDENTITY__ADMINRECREATE: false # 
+  IDENTITY__ADMINRECREATE: false
   ## @param env.IDENTITY__ALLOWPASSWORDAUTH Enable password auth. Set this to false if you want to disable local login, leaving only 3rd party login options
   ## 
   IDENTITY__ALLOWPASSWORDAUTH: "true"
@@ -205,7 +313,7 @@ env:
   LOGGING__HUMAN: false
   ## @param env.LOGGING__LEVEL Trace, Debug, Information, Warning, Error, Fatal
   ##
-  LOGGING__LEVEL: INFORMATION 
+  LOGGING__LEVEL: Warning
   ## @param env.LOGGING__LOGREQUESTS Set to false to disable logging of http requests.
   ##
   LOGGING__LOGREQUESTS: true
@@ -247,7 +355,23 @@ env:
 
   ## @param env.ASPNETCORE_URLS An override to ensure that kestrel starts on a non-privileged port
   ##
-  ASPNETCORE_URLS: http://+:80
+  ASPNETCORE_URLS: http://+:8080
+
+## @param autoscaling.enabled Enable autoscaling for the deployment
+autoscaling:
+  enabled: true
+  ## @param autoscaling.maxReplicas Maximum number of replicas
+  maxReplicas: 6
+  ## @param autoscaling.minReplicas Minimum number of replicas
+  minReplicas: 3
+  ## @param autoscaling.targetCPUUtilizationPercentage Target CPU utilization percentage
+  targetCPUUtilizationPercentage: 85
+
+## @param podDisruptionBudget.minAvailable Minimum number of available pods
+podDisruptionBudget:
+  minAvailable: 1
+  ## @param podDisruptionBudget.unhealthyPodEvictionPolicy Policy for evicting unhealthy pods
+  unhealthyPodEvictionPolicy: AlwaysAllow
 
 ## @section MongoDB parameters
 mongodb:


Reviews:
user: login: SebastianStehle
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-26T06:44:23Z
user: login: sinadarbouy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-26T10:27:46Z

Review comments:
diff_hunk: @@ -46,17 +46,34 @@ The command removes all the Kubernetes components associated with the chart and
 
 ### Global parameters
 
-| Name                       | Description                    | Value             |
-| -------------------------- | ------------------------------ | ----------------- |
-| `service.type`             | Kubernetes Service type        | `ClusterIP`       |
-| `service.port`             | Kubernetes Service port        | `80`              |
-| `deployment.replicaCount`  | Number of instances.           | `1`               |
-| `image.repository`         | Squidex image registry         | `squidex/squidex` |
-| `image.pullPolicy`         | Squidex image pull policy      | `IfNotPresent`    |
-| `runAsNonRoot`             |                                | `false`           |
-| `ingress.enabled`          | True to deploy an ingress      | `true`            |
-| `ingress.ingressClassName` | The ingress class.             | `nginx`           |
-| `ingress.hostName`         | The host name for the ingress. | `squidex.local`   |
+| Name                                               | Description                                                         | Value             |
+| -------------------------------------------------- | ------------------------------------------------------------------- | ----------------- |
+| `nameOverride`                                     | Override the name of the application.                               | `squidex`         |
+| `labels`                                           | Labels to add to the deployment                                     | `{}`              |
+| `service.type`                                     | Kubernetes Service type                                             | `ClusterIP`       |
+| `service.port`                                     | Kubernetes Service port                                             | `8080`            |
+| `deployment.replicaCount`                          | Number of replicas                                                  | `1`               |
+| `deployment.worker.replicaCount`                   | Number of worker instances                                          | `1`               |
path: helm/squidex7/README.md
user: login: SebastianStehle
body: This must not be set to anything other than 1.
created_at: 2025-04-26T06:44:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -46,17 +46,34 @@ The command removes all the Kubernetes components associated with the chart and
 
 ### Global parameters
 
-| Name                       | Description                    | Value             |
-| -------------------------- | ------------------------------ | ----------------- |
-| `service.type`             | Kubernetes Service type        | `ClusterIP`       |
-| `service.port`             | Kubernetes Service port        | `80`              |
-| `deployment.replicaCount`  | Number of instances.           | `1`               |
-| `image.repository`         | Squidex image registry         | `squidex/squidex` |
-| `image.pullPolicy`         | Squidex image pull policy      | `IfNotPresent`    |
-| `runAsNonRoot`             |                                | `false`           |
-| `ingress.enabled`          | True to deploy an ingress      | `true`            |
-| `ingress.ingressClassName` | The ingress class.             | `nginx`           |
-| `ingress.hostName`         | The host name for the ingress. | `squidex.local`   |
+| Name                                               | Description                                                         | Value             |
+| -------------------------------------------------- | ------------------------------------------------------------------- | ----------------- |
+| `nameOverride`                                     | Override the name of the application.                               | `squidex`         |
+| `labels`                                           | Labels to add to the deployment                                     | `{}`              |
+| `service.type`                                     | Kubernetes Service type                                             | `ClusterIP`       |
+| `service.port`                                     | Kubernetes Service port                                             | `8080`            |
+| `deployment.replicaCount`                          | Number of replicas                                                  | `1`               |
+| `deployment.worker.replicaCount`                   | Number of worker instances                                          | `1`               |
path: helm/squidex7/README.md
user: login: sinadarbouy
body: If I understand correctly, only one worker is supported, so deployment.worker.replicaCount is 1. 

When autoscaling is enabled, deployment.replicaCount is ignored — minReplicas is used instead(default minReplicas is 3).
You’re right, though — let’s set deployment.replicaCount to 3 when autoscaling is disabled.


addressed in [39a6baa](https://github.com/Squidex/squidex/pull/1211/commits/39a6baa7ebae4a26b08a51ecec7817e0f3d6429d)
created_at: 2025-04-26T10:27:45Z
author_association: CONTRIBUTOR

PR comments:
user: login: xSAVIKx
created_at: 2025-04-14T11:37:39Z
body: @sinadarbouy, this is something I'm looking forward so much! While you're doing these improvements, can you maybe consider adding `annotations` support for the deployments as well? This is essential to be able to e.g. add `istio` or `doppler` support.
author_association: NONE
user: login: sinadarbouy
created_at: 2025-04-14T11:45:32Z
body: > @sinadarbouy, this is something I'm looking forward so much! While you're doing these improvements, can you maybe consider adding `annotations` support for the deployments as well? This is essential to be able to e.g. add `istio` or `doppler` support.

yep! that’s already supported ✅
- 🏷️ Custom annotations, commands, and args are all configurable.
Now you can add deployment annotations via .Values.deployment.annotations.

i actually added it because i needed it for vault (secret manager) 😄
author_association: CONTRIBUTOR
user: login: SebastianStehle
created_at: 2025-04-16T19:53:06Z
body: I guess it looks okay. Not a helm expert here. The formatting of the tables in the Readme seems to be broken a little bit.
author_association: CONTRIBUTOR
user: login: SebastianStehle
created_at: 2025-04-24T13:23:34Z
body: Hi,

I also updated the helm chart to use a newer mongo version, it was very, very old. I Increased the version to 2.x. If you want to have your changes for 7 1.X as well, I recommend to make a new folder called 7_1 and apply your changes there and ideally also apply your changes to the 2.0 version. Please also remember to run the readme generator. It is linked in the README.md file.
author_association: CONTRIBUTOR
user: login: sinadarbouy
created_at: 2025-04-25T13:50:04Z
body: > Hi,
> 
> I also updated the helm chart to use a newer mongo version, it was very, very old. I Increased the version to 2.x. If you want to have your changes for 7 1.X as well, I recommend to make a new folder called 7_1 and apply your changes there and ideally also apply your changes to the 2.0 version. Please also remember to run the readme generator. It is linked in the README.md file.

Hi, thanks for the heads-up — I wasn’t aware of the README generator before, so I had added the README changes manually. I’ve now fixed that and re-generated it properly using the tool.

I also rebased your changes and bumped the chart version from 2.0.0 to 2.0.1.

Regarding moving the changes to a new folder: do you think that’s necessary in this case? The changes don’t really affect the structure significantly.
author_association: CONTRIBUTOR
user: login: SebastianStehle
created_at: 2025-04-25T20:51:01Z
body: If you want to upgrade your existing deployment I think it might be challenging with 2.0x because of the new mongo setup. Therefore: If you need it: I would create a new folder. Otherwise we are fine.
author_association: CONTRIBUTOR
user: login: sinadarbouy
created_at: 2025-04-25T21:02:05Z
body: > If you want to upgrade your existing deployment I think it might be challenging with 2.0x because of the new mongo setup. Therefore: If you need it: I would create a new folder. Otherwise we are fine.

In my case, I’m not using the MongoDB Helm chart—it’s disabled. I’m using a cloud MongoDB instead, so the new setup for MongoDB isn’t a challenge for me. Not sure about others, though.
author_association: CONTRIBUTOR