External data stores
Configure self-hosted Dreadnode to use external PostgreSQL, ClickHouse, or S3 services.
Data stores are chart configuration, applied by a redeploy. Configure each store in a Helm overlay, under Data Stores in the Admin Console, or with the matching KOTS ConfigValues items.
Dreadnode installs PostgreSQL, ClickHouse, and MinIO in the cluster by default. You can replace any of them with a managed service. Configure network access, credentials, backups, and availability at the external service before you redeploy Dreadnode.
Commands on this page use $NAMESPACE. For Helm, set it to your release
namespace. For Embedded Cluster, enter sudo ./dreadnode shell, then set it to
kotsadm. See Access Kubernetes.
PostgreSQL
Section titled “PostgreSQL”Set the external host and credentials, then disable the bundled PostgreSQL StatefulSet:
dreadnode-api: endpoints: database: external: my-rds-instance.region.rds.amazonaws.com credentials: database: source: externalSecret secretName: dreadnode-external-pg config: database: port: 5432 name: platform user: admin useSsl: true useIamAuth: false
dreadnode-base: postgresql: enabled: falseCreate the referenced Secret before upgrading:
kubectl -n "$NAMESPACE" create secret generic dreadnode-external-pg \ --from-literal=password='<db-password>'Open Config → Data Stores. Set PostgreSQL to Connect to an external database, then enter PostgreSQL Host, Port, Database Name, User, and Password. Keep Require SSL/TLS enabled for managed databases. The Admin Console creates the credential Secret.
apiVersion: kots.io/v1beta1kind: ConfigValuesspec: values: postgres_mode: value: postgres_external postgres_host: value: my-rds-instance.region.rds.amazonaws.com postgres_port: value: "5432" postgres_database: value: platform postgres_user: value: admin postgres_password: valuePlaintext: '<db-password>' postgres_use_ssl: value: "1" postgres_use_iam: value: "0"KOTS creates dreadnode-external-postgresql and stores the password there.
For Amazon RDS IAM authentication, set useIamAuth: true and annotate the API
service account with an IAM role that has rds-db:connect permission:
dreadnode-api: serviceAccount: annotations: eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/dreadnode-apiIn the Admin Console, enable Use AWS IAM authentication; the password field disappears. Put
the service-account annotation under Advanced Helm Values. In a ConfigValues file, set
postgres_use_iam.value to "1", omit postgres_password, and put the annotation in
advanced_helm_values.
The bundled inference proxy shares this database
Section titled “The bundled inference proxy shares this database”If you also run the bundled LiteLLM proxy,
it keeps its model catalog in a litellm schema on the same database. On
Embedded Cluster this is wired for you when you select an external database. On
Helm, point it at the same host:
dreadnode-litellm: database: host: <db-hostname> port: 5432 name: platform user: <db-user> useSsl: true secretName: dreadnode-external-pgThe configured user needs CREATE SCHEMA on that database — the proxy creates
the schema on first start. Without it, the proxy pod retries until the
privilege is granted.
IAM authentication is the one combination that does not work. LiteLLM connects with a static password and cannot mint RDS tokens, so an external database in IAM mode cannot host it. Keep the bundled PostgreSQL for the proxy, use password authentication, or run LiteLLM outside the cluster and connect the platform to it. On Embedded Cluster the proxy toggle is hidden when IAM authentication is enabled, and the chart fails the deploy with this message if the combination is reached through Helm.
ClickHouse
Section titled “ClickHouse”Set the external host and credentials, then disable the bundled ClickHouse StatefulSet:
dreadnode-api: endpoints: clickhouse: external: my-clickhouse.example.com credentials: clickhouse: source: externalSecret secretName: dreadnode-external-ch config: clickhouse: protocol: https port: 8443 database: default user: admin
dreadnode-base: clickhouse: enabled: falseCreate the referenced Secret before upgrading:
kubectl -n "$NAMESPACE" create secret generic dreadnode-external-ch \ --from-literal=admin-password='<ch-password>'Open Config → Data Stores. Set ClickHouse to Connect to ClickHouse Cloud or external, then enter ClickHouse Host, Port, Protocol, User, and Password. The Admin Console creates the credential Secret.
apiVersion: kots.io/v1beta1kind: ConfigValuesspec: values: clickhouse_mode: value: clickhouse_external clickhouse_host: value: my-clickhouse.example.com clickhouse_port: value: "8443" clickhouse_protocol: value: https clickhouse_user: value: admin clickhouse_password: valuePlaintext: '<ch-password>'KOTS creates dreadnode-external-clickhouse and stores the password there.
S3-compatible object storage
Section titled “S3-compatible object storage”Set the external endpoint and buckets, then disable bundled MinIO:
dreadnode-api: endpoints: s3: internal: '' external: https://s3.us-east-1.amazonaws.com credentials: s3: source: static # static | iam | minio secretName: dreadnode-external-s3 config: s3: region: us-east-1 buckets: pythonPackages: my-packages-bucket orgData: my-org-data-bucket userDataLogs: my-logs-bucket sdk: userDataRoleArn: arn:aws:iam::123456789012:role/dreadnode-user-data stsDurationSeconds: 3600
dreadnode-base: minio: enabled: falseCreate the referenced Secret before upgrading:
kubectl -n "$NAMESPACE" create secret generic dreadnode-external-s3 \ --from-literal=accessKeyId='<access-key-id>' \ --from-literal=secretAccessKey='<secret-access-key>'Open Config → Data Stores. Set Object Storage to Use external S3-compatible storage, then enter S3 Endpoint URL, S3 Access Key ID, S3 Secret Access Key, User Data IAM Role ARN (optional), S3 Region, and Scoped Credential Lifetime (seconds). The Admin Console creates the credential Secret.
Bucket names do not have dedicated fields. Set those through Advanced Helm Values.
apiVersion: kots.io/v1beta1kind: ConfigValuesspec: values: s3_mode: value: s3_external s3_endpoint: value: https://s3.us-east-1.amazonaws.com s3_access_key_id: value: '<access-key-id>' s3_secret_access_key: valuePlaintext: '<secret-access-key>' s3_user_data_role_arn: value: arn:aws:iam::123456789012:role/dreadnode-user-data s3_region: value: us-east-1 s3_sts_duration_seconds: value: "3600"KOTS creates dreadnode-external-s3. Put custom bucket names in the
advanced_helm_values item.
Leave internal empty for AWS S3. For another S3-compatible service, set it
to the endpoint that the API can reach. external is the endpoint returned
to clients for presigned URLs and must be reachable from their networks.
For Helm installs using IAM credentials, set source: iam, omit the credential Secret, and
configure workload identity on the API service account. The dedicated Embedded Cluster surface
supports static access keys only; use the Helm install path when the API itself must authenticate
to S3 through workload identity.
userDataRoleArn is the role the API assumes when it creates scoped workspace credentials. It
must trust the API identity and allow access to the organization data bucket.
stsDurationSeconds must be no greater than 3600 — the API rejects larger values at startup —
and the role’s MaxSessionDuration must be at least the configured value. Keep Scoped Credential
Lifetime at or below 3600 in the Admin Console and ConfigValues file.
The dedicated Embedded Cluster fields cover the endpoint, credentials, user-data role, region, and credential lifetime. Only bucket-name overrides need Advanced Helm Values; that document merges after the dedicated fields during deployment.
Verify the connection
Section titled “Verify the connection”Redeploy Dreadnode, then watch the API migration and startup logs:
kubectl -n "$NAMESPACE" logs deploy/dreadnode-api -c migrationskubectl -n "$NAMESPACE" logs deploy/dreadnode-apiConnection, authentication, and bucket errors appear during startup. When the API is ready, verify the platform health endpoint:
curl https://dreadnode.example.com/api/v1/healthUse the configured scheme and domain. Back up external services with their native tools; Dreadnode does not manage their backup lifecycle.