Kubernetes
Use the official private Helm chart when you want a persistent self-hosted Synth instance. For a complete first install, use Helm + CaSc. This page explains the deployment shape and what to verify.
For guided single-pod installs, use the standalone-pvc shape: one app pod,
one PVC mounted at /var/lib/synth, and Secrets for any provider keys,
registry auth, and the Synth license key.
standalone-pvc is persistent but not HA. Do not raise replicaCount above
1; the chart renders with a Recreate strategy to protect the single-writer
SQLite/filesystem state.
Install Shape
Private registry: official Synth image and Helm chart
Kubernetes Secrets: optional provider keys, license key, image pull key
Helm values: runtime settings plus synth.casc.raw
Helm chart: renders CaSc and imports it before app startup
PVC: stores Synth data under /var/lib/synth
Values To Set First
For any public install, set the official image, public URL, host allowlist, ingress, persistence, license Secret, and runtime Secret. Add provider defaults when model-backed jobs are part of the deployment:
image:
repository: us-central1-docker.pkg.dev/project-96337d0a-4d88-427b-af7/synth/synth
tag: latest
digest: sha256:...
imagePullSecrets:
- name: synth-registry-pull
synth:
publicUrl: https://synth.example.com
existingLicenseSecret: synth-license
defaultProvider: opencode
defaultModel: gpt-5.4-mini
security:
allowedHosts:
- synth.example.com
corsOrigins:
- https://synth.example.com
providers:
opencode:
enabled: true
baseUrl: https://opencode.ai/zen/v1
defaultModel: gpt-5.4-mini
secrets:
existingSecret: synth-runtime-secrets
persistence:
enabled: true
Canonical Project retrieval does not require a provider. When enabling an
explicit model-assisted job, add provider keys through
Kubernetes Secrets or your secret manager. Do not commit real keys to
values.yaml.
Amazon Bedrock Provider
Bedrock is configured under synth.providers.bedrock. Always set
enabled: true, regionName, and a model id that is available in that AWS
region.
synth:
defaultProvider: bedrock
defaultModel: amazon.nova-micro-v1:0
providers:
bedrock:
enabled: true
regionName: us-east-1
defaultModel: amazon.nova-micro-v1:0
Pick one auth mode:
- EKS IRSA or the AWS default credential chain. Annotate the ServiceAccount
and set
serviceAccount.automountServiceAccountToken: true.
serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/synth-bedrock
automountServiceAccountToken: true
- Existing Secret with AWS access keys. The Secret should contain
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY; addAWS_SESSION_TOKENfor temporary credentials.
kubectl -n "$SYNTH_NAMESPACE" create secret generic synth-bedrock-aws \
--from-literal=AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" \
--from-literal=AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" \
--dry-run=client -o yaml | kubectl apply -f -
synth:
providers:
bedrock:
enabled: true
regionName: us-east-1
existingAccessKeySecret: synth-bedrock-aws
- Existing Secret with a Bedrock bearer token.
kubectl -n "$SYNTH_NAMESPACE" create secret generic synth-bedrock-bearer \
--from-literal=BEDROCK_BEARER_TOKEN="$BEDROCK_BEARER_TOKEN" \
--dry-run=client -o yaml | kubectl apply -f -
synth:
providers:
bedrock:
enabled: true
regionName: us-east-1
existingBearerTokenSecret: synth-bedrock-bearer
Before installing, render the chart and confirm Bedrock secrets are not in the CaSc ConfigMap:
helm template synth "$SYNTH_HELM_CHART" --version "$SYNTH_HELM_CHART_VERSION" \
-f values.k8s.yaml >/tmp/synth-rendered.yaml
grep -n "bedrock:" -A8 /tmp/synth-rendered.yaml
grep -n "BEDROCK_REGION\\|AWS_ACCESS_KEY_ID\\|BEDROCK_BEARER_TOKEN" /tmp/synth-rendered.yaml
Okta SSO With Bedrock
Okta and Bedrock are independent: Okta authenticates people, while Bedrock is used only by configured model-assisted ingestion jobs. Canonical Project search and exact-page reads remain provider-free.
For an EKS deployment using IRSA and Okta, create only the Okta secret and keep both the OIDC client secret and AWS credentials out of Git:
kubectl -n "$SYNTH_NAMESPACE" create secret generic synth-okta \
--from-literal=client-secret="$OKTA_CLIENT_SECRET" \
--dry-run=client -o yaml | kubectl apply -f -
synth:
publicUrl: https://synth.customer.example
existingLicenseSecret: synth-license
defaultProvider: bedrock
defaultModel: us.anthropic.claude-haiku-4-5-20251001-v1:0
providers:
bedrock:
enabled: true
regionName: us-east-1
defaultModel: us.anthropic.claude-haiku-4-5-20251001-v1:0
sso:
enabled: true
issuerUrl: https://customer.okta.com/oauth2/default
clientId: 0oa-customer-synth
existingSecret: synth-okta
existingSecretKey: client-secret
redirectUri: https://synth.customer.example/api/auth/oidc/callback
scopes: [openid, profile, email, groups]
autoProvision: true
defaultRole: member
adminClaim: groups
adminGroupValue: synth-admins
serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/synth-bedrock
automountServiceAccountToken: true
Before rollout, replace every example hostname, issuer, client ID, role ARN, region, model route, and group name. The Okta redirect URI must match exactly; the Bedrock model route must be enabled in the configured AWS region.
Install
Use the private OCI chart supplied with your license:
export SYNTH_NAMESPACE=synth
kubectl create namespace "$SYNTH_NAMESPACE" --dry-run=client -o yaml | kubectl apply -f -
cat secrets/gcp-artifact-registry-pull-key.json | helm registry login us-central1-docker.pkg.dev \
--username _json_key \
--password-stdin
kubectl -n "$SYNTH_NAMESPACE" create secret docker-registry synth-registry-pull \
--docker-server=us-central1-docker.pkg.dev \
--docker-username=_json_key \
--docker-password="$(cat secrets/gcp-artifact-registry-pull-key.json)" \
--dry-run=client -o yaml | kubectl apply -f -
kubectl -n "$SYNTH_NAMESPACE" create secret generic synth-runtime-secrets \
--from-literal=OPENCODE_API_KEY="$OPENCODE_API_KEY" \
--dry-run=client -o yaml | kubectl apply -f -
kubectl -n "$SYNTH_NAMESPACE" create secret generic synth-license \
--from-file=license-key=/secure/path/synth-license-key.txt \
--dry-run=client -o yaml | kubectl apply -f -
helm upgrade --install synth \
oci://us-central1-docker.pkg.dev/project-96337d0a-4d88-427b-af7/synth/charts/synth \
--namespace "$SYNTH_NAMESPACE" \
-f values.k8s.yaml \
--wait \
--timeout 10m
Project And Watcher Values
For a Project with a remote Git backend and a watcher, use the explicit
synth.casc.raw form. Helm mounts the CaSc document, Synth imports it on
startup, and the Project config is written under
/var/lib/synth/projects/<project>/.synth/config.yaml.
The chart also has a small synth.projects shorthand for simple generated
CaSc, but use synth.casc.raw when you need a complete copy-pasteable project,
backend, credential, and watcher configuration.
synth:
casc:
raw: |
global_settings:
default_provider: opencode
default_model: gpt-5.4-mini
providers:
opencode:
enabled: true
credential_id: helm-opencode
base_url: https://opencode.ai/zen/v1
default_model: gpt-5.4-mini
credentials:
helm-opencode:
type: opencode_api_key
name: Helm OpenCode API key
data:
api_key:
env: OPENCODE_API_KEY
github-read-token:
type: github_pat
name: GitHub read token
data:
token:
env: GITHUB_PAT
projects:
docs:
backend:
type: git
config:
remote_url: https://github.com/your-org/synth-knowledge.git
branch: main
auto_push: true
auto_pull: true
sync_on_create: true
project_subdir: projects/docs
credential_id: github-read-token
schema:
categories:
- name: Guides
directory: guides
description: How-to guides and setup workflows.
- name: Reference
directory: reference
description: API, CLI, and configuration reference.
- name: Tutorials
directory: tutorials
description: Step-by-step learning material.
- name: Troubleshooting
directory: troubleshooting
description: Known issues and remediation steps.
watchers:
docs-main:
type: git
repo: https://github.com/your-org/docs-site.git
branch: main
interval: 300
auto_start: true
credential: github-read-token
files:
rules:
- name: Public docs
include:
- "docs/**/*.{md,mdx,markdown}"
exclude:
- "**/node_modules/**"
- "**/build/**"
secrets:
existingSecret: synth-runtime-secrets
The runtime Secret named by secrets.existingSecret must contain the keys
referenced by CaSc credentials, such as OPENCODE_API_KEY and GITHUB_PAT.
The project schema belongs at projects.<name>.schema.categories; older exports
may call this field scheme, but schema is the canonical CaSc key.
Use auto_start: false if you want to inspect the imported watcher before the
first clone.
Verify
kubectl -n synth rollout status deploy/synth --timeout=10m
kubectl -n synth get deploy,svc,ingress,pvc
curl -fsS https://synth.example.com/health
Then sign in and confirm Settings -> Models, Projects, and Watchers show the expected imported configuration.
Finally, open Explore, search for a phrase from an approved source file, and open the returned exact page. Confirm that the Project is ready, the result comes from a real watched page, and its provenance identifies the expected source. Kubernetes health does not by itself prove that Project evidence was published successfully.
MCP Behind HTTPS
Set SYNTH_PUBLIC_URL or the chart equivalent so generated MCP config points to the external HTTPS origin:
https://synth.example.com/api/mcp/
Production Checklist
- persistent volume enabled
- HTTPS ingress configured
- provider credentials loaded from secrets
- CaSc imported from Helm values
- first admin created
- backup plan for
SYNTH_HOME - scoped API keys for agents
- organization credentials created before private watchers start
For single-VM POCs, Docker Compose is simpler. For team use, Kubernetes is the clean path.