Deploying SelectZero
Prerequisites
The minimum requirements for the server or cloud instance hosting the application are as follows:
CPU: 2 core
RAM: 4GB
HDD: A minimum of 10GB of free space
If you are doing production deployment, please also follow information about securing deployment for production
Encryption key
SelectZero platform encrypts all user secrets and files at rest. On initial deployment, encryption key will be automatically generated if not provided by environment variables. Generated encryption key will be stored in "database" volume under "encryption.key" with only running user access rights.
Quick start
Fastest way of deploying SelectZero is by using our predefined docker compose file, which takes care of the configuration for you. Make sure you are in the preferred directory on the machine.
Downloading docker compose and launching it:
If you need more precise configuration you can simply download the docker-compose:
Modify it based on your needs and then run it:
After running the platform, you can acquire initial admin password (application boot up might take a few seconds):
Deployment
Download the latest version of JAR from https://selectzero.com/downloads/
To run JAR application, use command:
-Xmx4g – Specifies the amount of memory that can be used by Java – in this case 4GB
-Dserver.port=8090 – Defining SelectZero application port (8090 is also default port if not provided)
It is recommended to run the Java file as a service.
For hosting your application on your cloud instance, make sure you have a connection to docker hub.
You can find latest versions here
Deploy with docker
Pull docker image
docker pull selectzero/selectzero:2026.7.3Run container
docker run -d -v {local_path}/logs:/usr/app/logs -v {local_path}/database:/usr/app/database -v {local_path}/drivers:/usr/app/drivers -v {local_path}/reports:/usr/app/reports -v {local_path}/keys:/usr/app/keys -p 8090:8090 -e JAVA_OPTIONS='-Xmx4g' selectzero/selectzero:2026.7.3-v {local_path}/logs:/usr/app/logs
Logs storage
-v {local_path}/database:/usr/app/database
DQM local database
-v {local_path}/drivers:/usr/app/drivers
JAR connectors storage
-v {local_path}/reports:/usr/app/reports
Reports and results
-v {local_path}/keys:/usr/app/keys
Key files storage such as BigQuery JSON keys and application certificate keystore
-p 8090:8090
Port mapping for exposing DQM application at port 8090
selectzero/selectzero:2026.7.3
Image from dockerhub, latest tag is also available
Validate that DQM container is running
docker ps
Docker compose is the easiest way to deploy/manage DQM with docker containers
Deploy with docker compose
Create docker-compose.yml
services: selectzero: container_name: selectzero image: selectzero/selectzero:2026.7.3 ports: - 8090:8090 volumes: - ./logs:/usr/app/logs - ./database:/usr/app/database - ./drivers:/usr/app/drivers - ./reports:/usr/app/reports - ./keys:/usr/app/keys environment: JAVA_OPTIONS: -Xmx4gRun docker compose
docker compose up -d
Deploying on kubernetes
Create a PersistentVolumeClaim using your cloud provider's storage class. Choose the tab matching your environment:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: selectzero-storage-claim spec: storageClassName: gp3 accessModes: - ReadWriteOnce resources: requests: storage: 20GiUses the Amazon EBS gp3 storage class (default on most EKS clusters). Ensure the EBS CSI driver is installed.
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: selectzero-storage-claim spec: storageClassName: managed-csi accessModes: - ReadWriteOnce resources: requests: storage: 20GiUses Azure Managed Disk (CSI) storage class, available by default on AKS clusters.
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: selectzero-storage-claim spec: storageClassName: standard-rwo accessModes: - ReadWriteOnce resources: requests: storage: 20GiUses GCE Persistent Disk (CSI) storage class, available by default on GKE clusters.
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: selectzero-storage-claim spec: accessModes: - ReadWriteOnce resources: requests: storage: 20GiOmitting
storageClassNameuses the cluster's default storage class. Verify your default class provides persistent block storage (nothostPath) by running:kubectl get storageclassCreate resource file selectzero.yaml
--- apiVersion: apps/v1 kind: Deployment metadata: name: selectzero-deployment spec: selector: matchLabels: app: selectzero replicas: 1 # SelectZero is limited to one replica due to sessions strategy: type: RollingUpdate template: metadata: labels: app: selectzero spec: volumes: - name: selectzero-storage persistentVolumeClaim: claimName: selectzero-storage-claim containers: - name: selectzero image: selectzero/selectzero:2026.7.3 # Modify version tag resources: limits: memory: 4Gi requests: memory: 4Gi env: - name: JAVA_OPTIONS value: -XX:MaxRAMPercentage=80.0 ports: - containerPort: 8090 volumeMounts: - mountPath: "/usr/app/database" name: selectzero-storage subPath: database - mountPath: "/usr/app/logs" name: selectzero-storage subPath: logs - mountPath: "/usr/app/drivers" name: selectzero-storage subPath: drivers - mountPath: "/usr/app/reports" name: selectzero-storage subPath: reports - mountPath: "/usr/app/keys" name: selectzero-storage subPath: keys - mountPath: "/usr/app/tempFiles" name: selectzero-storage subPath: tempFiles --- apiVersion: v1 kind: Service metadata: name: selectzero labels: app: selectzero spec: type: NodePort ports: - port: 80 targetPort: 8090 selector: app: selectzeroApply using kubectl
kubectl apply -f selectzero.yaml
S3 storage mode (stateless Kubernetes)
For Kubernetes environments with a "no persistent volumes" policy, SelectZero can store all durable files (execution results, test suite reports, uploaded data source files, JDBC drivers, custom logo) in an Amazon S3 bucket instead of a persistent volume. Pods become fully stateless: local disk is used only as an ephemeral working copy (emptyDir), and the entire cluster can be rebuilt from manifests without data loss.
By default all files are encrypted by the application before they reach the bucket - S3 only ever holds ciphertext, and the encryption key never leaves your secrets manager.
Alternatively, set DQM_FILE_ENCRYPTION=false to delegate encryption at rest entirely to the storage layer: files are written as-is and the bucket's server-side encryption (SSE-S3 or SSE-KMS) protects them. The main benefit is key management - rotating a KMS key is handled by AWS and never requires re-encrypting stored files, whereas rotating DQM_ENCRYPTION_KEY with application-side file encryption would. DQM_ENCRYPTION_KEY is still required in S3 mode either way, because it also protects secrets stored in database columns (connection passwords, certificates), which S3 encryption cannot cover. File names keep their .enc suffix in both modes.
Requirements
External PostgreSQL as the application database (SQLite is not supported in S3 mode)
DQM_ENCRYPTION_KEYmust be provided from your secrets manager - the application refuses to start in S3 mode without it, because a locally generated key would not survive a pod restart and would make the encrypted files in the bucket unreadableAn S3 bucket and IAM permissions:
s3:ListBucketon the bucket,s3:GetObject,s3:PutObject,s3:DeleteObjecton the bucket contents
At startup in S3 mode the application lists the bucket once to verify the configuration. If the bucket cannot be reached - wrong name or region, missing s3:ListBucket, or credentials that do not resolve - the application refuses to start and logs the reason, rather than running with file storage that would fail later during a scheduled job.
Configuration
Variable name | Explanation |
|---|---|
SZ_STORAGE_MODE |
|
SZ_STORAGE_S3_BUCKET | Bucket name for durable file storage |
SZ_STORAGE_S3_REGION | AWS region of the bucket, e.g. |
SZ_STORAGE_S3_PREFIX | Optional key prefix inside the bucket, e.g. |
SZ_STORAGE_S3_ACCESS_KEY | Optional. Leave empty to use the AWS default credential chain - on EKS attach an IAM role to the service account (IRSA), no secrets required |
SZ_STORAGE_S3_SECRET_KEY | Optional, pairs with the access key |
DQM_FILE_ENCRYPTION |
|
Reading a credential failure
When credentials cannot be resolved, the AWS SDK reports every provider it tried. Only the provider matching your setup matters; the others always fail and can be ignored:
Running with an IAM role (IRSA or EKS Pod Identity), the messages about
AWS_ACCESS_KEY_IDare expected. A role never produces an access key.Profile file contained no credentials for profile 'default'refers to an AWS credentials profile (~/.aws/credentials), not to a Kubernetes service account. The container has no such file, so this line is normal and unrelated to which service account the pod runs under.With IRSA, the line to check is the web identity one. The pod's service account must carry the
eks.amazonaws.com/role-arnannotation, which makes EKS injectAWS_ROLE_ARNandAWS_WEB_IDENTITY_TOKEN_FILEinto the container. Verify withkubectl exec <pod> -- env | grep AWS_; the service account itself is selected byspec.serviceAccountNamein the pod spec, never by application configuration.
Security model with file encryption disabled
When DQM_FILE_ENCRYPTION=false, encryption at rest is provided by the infrastructure instead of the application. Verify and configure the following:
Bucket encryption. Check what the bucket applies with
aws s3api get-bucket-encryption --bucket <bucket>. Every S3 bucket encrypts objects at rest by default (SSE-S3/AES256). For customer-controlled key rotation, configure the bucket with SSE-KMS and a customer-managed KMS key, and enable S3 Bucket Keys to reduce KMS request costs (SelectZero writes many small objects). Rotating the KMS key never requires re-encrypting stored objects.Per-object proof.
aws s3api head-object --bucket <bucket> --key "reports/results/<file>"returns aServerSideEncryptionfield (AES256oraws:kmswith the key id) - evidence that a specific object is encrypted at rest.IAM. With SSE-KMS the application's role additionally needs
kms:GenerateDataKeyandkms:Decrypton the key, on top of the S3 permissions listed under Requirements.Bucket policies. The application sends no explicit encryption headers - bucket default encryption applies to its uploads. A bucket policy that denies
PutObjectrequests lacking an explicitx-amz-server-side-encryptionheader will therefore reject all uploads; rely on bucket default encryption instead of such deny policies.Local working copies. The pod's ephemeral volume holds plaintext working copies of uploaded files and cached results while the pod runs (with file encryption enabled it holds plaintext temporary data during query execution as well - only the durable copies differ). At-rest protection for the node comes from volume encryption (e.g. encrypted EBS), which is the same posture as any database workload. For the strictest setup, back the working directories with
emptyDir: {medium: Memory}sized for the full uploaded-file set plus cache - plaintext then never touches a disk.
Secrets stored in database columns (connection passwords, certificates, tokens) are encrypted with DQM_ENCRYPTION_KEY in every mode - the flag only affects files.
Kubernetes example
The deployment differs from the persistent volume variant in three ways: no PersistentVolumeClaim (all volumes are emptyDir), the Recreate update strategy (avoids two pods overlapping on the same working files), and the storage/encryption environment variables.
Startup hydration
On every pod start in S3 mode, SelectZero restores its working directories (uploaded data source files, drivers, logo) from the bucket before the application becomes ready. Progress is visible in the system log:
Startup time grows with the amount of uploaded data (downloads run in parallel; roughly 1-3 minutes for 15GB of uploaded files in-region). Configure the pod's startupProbe with enough headroom for your data volume so Kubernetes does not restart the pod mid-hydration.
Choosing underlying database
SelectZero supports two underlying database types:
SQLite - default deployment database. Local file based database
Postgres - Separate database instance for better performance and scaling. Can be enabled via UI or directly from environment variables
Supported environment variables
Variable name | Explanation |
|---|---|
DQM_ENCRYPTION_KEY | Custom encryption key for encrypting underlying secrets, and files while file encryption is enabled |
DQM_FILE_ENCRYPTION |
|
SPRING_PROFILES_ACTIVE | Profile to run platform with (default 'on-prem'). Available profiles are on-prem, secure-session |
SZ_JDBC_URL | Postgres JDBC url for application database |
SZ_DATABASE_USER | Postgres JDBC user for application database |
SZ_DATABASE_PASSWORD | Postgres JDBC password for application database |
SZ_DATABASE_SSL_MODE | Postgres JDBC SSL Mode for application database (NONE, SSL, SSL_VERIFY). |
SZ_STORAGE_MODE | Durable file storage backend: |
Updating SelectZero version
Update JAR
Download the latest version of JAR from https://selectzero.com/downloads/
Stop the old JAR service
systemctl stop {service-name}Run new JAR
java -XX:TieredStopAtLevel=1 -Dspring.jmx.enabled=false -Xmx4g -Dserver.port=8090 -jar SelectZero_2026.7.3.jar
Update docker container
Pull new docker image
docker pull selectzero/selectzero:2026.7.3Look for old container name
docker psStop old container
docker stop {container-name}Run container with new version
docker run -d -v {local_path}/logs:/usr/app/logs -v {local_path}/database:/usr/app/database -v {local_path}/drivers:/usr/app/drivers -v {local_path}/reports:/usr/app/reports -v {local_path}/keys:/usr/app/keys -p 8090:8090 -e JAVA_OPTIONS='-Xmx4g' selectzero/selectzero:2026.7.3Validate that SelectZero container is running with new version
docker ps
Update docker compose
Modify existing docker-compose.yml
services: selectzero: container_name: selectzero image: selectzero/selectzero:2026.7.3 # Change version ports: - 8090:8090 volumes: - ./logs:/usr/app/logs - ./database:/usr/app/database - ./drivers:/usr/app/drivers - ./reports:/usr/app/reports - ./keys:/usr/app/keys environment: JAVA_OPTIONS: -Xmx4gRun docker compose
docker compose up -d
Update kubernetes
Modify resource file selectzero.yaml
... containers: - name: selectzero image: selectzero/selectzero:2026.7.3 # Modify version tag resources: limits: memory: 4Gi requests: memory: 4Gi ...Apply using kubectl
kubectl apply -f selectzero.yaml
Fixing folder rights for non-root user
From version 2023.10 SelectZero container is running on non-root user "dqm". This is due to security reasons. "dqm" user uses default groups UID:1000 GID:1000. In case SelectZero container startup should give folder access rights, we have prepared a few fix scripts for assigning correct user rights to folders. This is a one time action and will work as expected in the future. It won't affect new installs, unless using direct docker bind mount to host system.
Fix folder rights
Stop existing container
docker stop {container_name}Run busybox container to fix folder permissions
docker run --rm -v {local_path}/logs:/usr/app/logs -v {local_path}/database:/usr/app/database -v {local_path}/drivers:/usr/app/drivers -v {local_path}/reports:/usr/app/reports -v {local_path}/keys:/usr/app/keys busybox:latest sh -c "chown -R 1000:1000 /usr/app"Run the original container with fixed folder permissions
docker run -d -v {local_path}/logs:/usr/app/logs -v {local_path}/database:/usr/app/database -v {local_path}/drivers:/usr/app/drivers -v {local_path}/reports:/usr/app/reports -v {local_path}/keys:/usr/app/keys -p 8090:8090 -e JAVA_OPTIONS='-Xmx4g' {image_id}
Fix folder rights
Modify existing docker-compose.yml to include startup service
version: "3.7" services: busybox: container_name: busybox-folders image: busybox volumes: - ./logs:/usr/app/logs - ./database:/usr/app/database - ./drivers:/usr/app/drivers - ./reports:/usr/app/reports - ./keys:/usr/app/keys command: ["chown", "-R", "1000:1000", "/usr/app/"] selectzero: container_name: selectzero-non-root image: "selectzero/selectzero:2026.7.3" ports: - "8090:8090" volumes: - ./logs:/usr/app/logs - ./database:/usr/app/database - ./drivers:/usr/app/drivers - ./reports:/usr/app/reports - ./keys:/usr/app/keys environment: JAVA_OPTIONS: "-Xmx2g -Djava.security.egd=:/dev/urandom" depends_on: busybox: condition: service_completed_successfullyRe-apply docker compose
docker compose up -d
Fix folder rights
Modify deployment resource to include init container
... spec: volumes: - name: selectzero-storage persistentVolumeClaim: claimName: selectzero-storage-claim initContainers: - name: folder-rights-fix image: busybox:latest securityContext: runAsUser: 0 imagePullPolicy: Always command: ["chown", "-R", "1000:1000", "/usr/app/"] volumeMounts: - mountPath: "/usr/app/database" name: {storage-name} subPath: database - mountPath: "/usr/app/logs" name: {storage-name} subPath: logs - mountPath: "/usr/app/drivers" name: {storage-name} subPath: drivers - mountPath: "/usr/app/reports" name: {storage-name} subPath: reports - mountPath: "/usr/app/keys" name: {storage-name} subPath: keys containers: - name: selectzero ...Add security context to main deployment spec
... apiVersion: apps/v1 kind: Deployment metadata: name: selectzero-deployment spec: securityContext: runAsUser: 1000 fsGroup: 1000 ...Re-apply kubernetes resource
kubectl apply -f selectzero.yaml
Securing deployment for production
For production environments we recommend adding extra security options to make the platform more resilient.
Adding host headers
Enabling secure session cookies with secure-session profile (requires https)